summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.yml1
-rw-r--r--.github/pull_request_template.md15
-rw-r--r--.github/workflows/checks.yml46
-rw-r--r--.github/workflows/close-if-no-reply.yml12
-rw-r--r--.gitmodules4
-rw-r--r--CONTRIBUTING.md43
-rw-r--r--README.md9
-rw-r--r--app/build.gradle14
-rw-r--r--app/proguard.cfg4
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java38
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/event/FeedItemEventListener.java46
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java11
-rw-r--r--app/src/main/assets/LICENSE_ANDROID_ICONIFY.txt18
-rw-r--r--app/src/main/assets/LICENSE_TRIANGLE_LABEL_VIEW.txt13
-rw-r--r--app/src/main/assets/licenses.xml24
-rw-r--r--app/src/main/java/de/danoeh/antennapod/PodcastApp.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java11
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java68
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java68
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java9
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/SwipeActionsDialog.java52
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/TimeRangeDialog.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java13
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java16
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java9
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java30
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/DownloadsPreferencesFragment.java16
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java188
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java44
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/about/ContributorsPagerFragment.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/dialog/PreferenceSwitchDialog.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/swipeactions/SwipeActions.java22
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/LiftOnScrollListener.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/LocalDeleteModal.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/viewholder/DownloadLogItemViewHolder.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/viewholder/HorizontalItemViewHolder.java4
m---------app/src/main/play0
-rw-r--r--app/src/main/play/contact-email.txt1
-rw-r--r--app/src/main/play/contact-website.txt1
-rw-r--r--app/src/main/play/default-language.txt1
-rw-r--r--app/src/main/play/listings/ar/full-description.txt31
-rw-r--r--app/src/main/play/listings/ar/short-description.txt1
-rw-r--r--app/src/main/play/listings/ar/title.txt1
-rw-r--r--app/src/main/play/listings/bg/full-description.txt31
-rw-r--r--app/src/main/play/listings/bg/short-description.txt1
-rw-r--r--app/src/main/play/listings/bg/title.txt1
-rw-r--r--app/src/main/play/listings/ca/full-description.txt31
-rw-r--r--app/src/main/play/listings/ca/short-description.txt1
-rw-r--r--app/src/main/play/listings/ca/title.txt1
-rw-r--r--app/src/main/play/listings/cs-CZ/full-description.txt31
-rw-r--r--app/src/main/play/listings/cs-CZ/short-description.txt1
-rw-r--r--app/src/main/play/listings/cs-CZ/title.txt1
-rw-r--r--app/src/main/play/listings/da-DK/full-description.txt31
-rw-r--r--app/src/main/play/listings/da-DK/short-description.txt1
-rw-r--r--app/src/main/play/listings/da-DK/title.txt1
-rw-r--r--app/src/main/play/listings/de-DE/full-description.txt31
-rw-r--r--app/src/main/play/listings/de-DE/graphics/large-tablet-screenshots/tablet.pngbin604491 -> 0 bytes
-rw-r--r--app/src/main/play/listings/de-DE/graphics/phone-screenshots/00.pngbin1073593 -> 0 bytes
-rw-r--r--app/src/main/play/listings/de-DE/graphics/phone-screenshots/01.pngbin975991 -> 0 bytes
-rw-r--r--app/src/main/play/listings/de-DE/graphics/phone-screenshots/02.pngbin931300 -> 0 bytes
-rw-r--r--app/src/main/play/listings/de-DE/graphics/phone-screenshots/03.pngbin634159 -> 0 bytes
-rw-r--r--app/src/main/play/listings/de-DE/graphics/phone-screenshots/04.pngbin832513 -> 0 bytes
-rw-r--r--app/src/main/play/listings/de-DE/graphics/phone-screenshots/05.pngbin1057683 -> 0 bytes
-rw-r--r--app/src/main/play/listings/de-DE/short-description.txt1
-rw-r--r--app/src/main/play/listings/de-DE/title.txt1
-rw-r--r--app/src/main/play/listings/en-US/full-description.txt31
-rw-r--r--app/src/main/play/listings/en-US/graphics/feature-graphic/feature-graphic.pngbin154355 -> 0 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/icon/icon.pngbin77232 -> 0 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/large-tablet-screenshots/tablet.pngbin605931 -> 0 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/phone-screenshots/00.pngbin1062876 -> 0 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/phone-screenshots/01.pngbin953326 -> 0 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/phone-screenshots/02.pngbin563909 -> 0 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/phone-screenshots/03.pngbin625108 -> 0 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/phone-screenshots/04.pngbin791607 -> 0 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/phone-screenshots/05.pngbin951698 -> 0 bytes
-rw-r--r--app/src/main/play/listings/en-US/graphics/tv-banner/tv-banner.pngbin290613 -> 0 bytes
-rw-r--r--app/src/main/play/listings/en-US/short-description.txt1
-rw-r--r--app/src/main/play/listings/en-US/title.txt1
-rw-r--r--app/src/main/play/listings/es-ES/full-description.txt31
-rw-r--r--app/src/main/play/listings/es-ES/graphics/phone-screenshots/00.pngbin1059048 -> 0 bytes
-rw-r--r--app/src/main/play/listings/es-ES/graphics/phone-screenshots/01.pngbin950880 -> 0 bytes
-rw-r--r--app/src/main/play/listings/es-ES/graphics/phone-screenshots/02.pngbin566507 -> 0 bytes
-rw-r--r--app/src/main/play/listings/es-ES/graphics/phone-screenshots/03.pngbin631537 -> 0 bytes
-rw-r--r--app/src/main/play/listings/es-ES/graphics/phone-screenshots/04.pngbin790678 -> 0 bytes
-rw-r--r--app/src/main/play/listings/es-ES/graphics/phone-screenshots/05.pngbin944519 -> 0 bytes
-rw-r--r--app/src/main/play/listings/es-ES/short-description.txt1
-rw-r--r--app/src/main/play/listings/es-ES/title.txt1
-rw-r--r--app/src/main/play/listings/et/full-description.txt31
-rw-r--r--app/src/main/play/listings/et/short-description.txt1
-rw-r--r--app/src/main/play/listings/et/title.txt1
-rw-r--r--app/src/main/play/listings/eu-ES/full-description.txt31
-rw-r--r--app/src/main/play/listings/eu-ES/short-description.txt1
-rw-r--r--app/src/main/play/listings/eu-ES/title.txt1
-rw-r--r--app/src/main/play/listings/fa/full-description.txt31
-rw-r--r--app/src/main/play/listings/fa/short-description.txt1
-rw-r--r--app/src/main/play/listings/fa/title.txt1
-rw-r--r--app/src/main/play/listings/fi-FI/full-description.txt31
-rw-r--r--app/src/main/play/listings/fi-FI/short-description.txt1
-rw-r--r--app/src/main/play/listings/fi-FI/title.txt1
-rw-r--r--app/src/main/play/listings/fr-FR/full-description.txt31
-rw-r--r--app/src/main/play/listings/fr-FR/graphics/phone-screenshots/00.pngbin1059937 -> 0 bytes
-rw-r--r--app/src/main/play/listings/fr-FR/graphics/phone-screenshots/01.pngbin958188 -> 0 bytes
-rw-r--r--app/src/main/play/listings/fr-FR/graphics/phone-screenshots/02.pngbin558621 -> 0 bytes
-rw-r--r--app/src/main/play/listings/fr-FR/graphics/phone-screenshots/03.pngbin627704 -> 0 bytes
-rw-r--r--app/src/main/play/listings/fr-FR/graphics/phone-screenshots/04.pngbin800579 -> 0 bytes
-rw-r--r--app/src/main/play/listings/fr-FR/graphics/phone-screenshots/05.pngbin950236 -> 0 bytes
-rw-r--r--app/src/main/play/listings/fr-FR/short-description.txt1
-rw-r--r--app/src/main/play/listings/fr-FR/title.txt1
-rw-r--r--app/src/main/play/listings/gl-ES/full-description.txt31
-rw-r--r--app/src/main/play/listings/gl-ES/short-description.txt1
-rw-r--r--app/src/main/play/listings/gl-ES/title.txt1
-rw-r--r--app/src/main/play/listings/hi-IN/full-description.txt31
-rw-r--r--app/src/main/play/listings/hi-IN/short-description.txt1
-rw-r--r--app/src/main/play/listings/hi-IN/title.txt1
-rw-r--r--app/src/main/play/listings/hu-HU/full-description.txt31
-rw-r--r--app/src/main/play/listings/hu-HU/short-description.txt1
-rw-r--r--app/src/main/play/listings/hu-HU/title.txt1
-rw-r--r--app/src/main/play/listings/it-IT/full-description.txt31
-rw-r--r--app/src/main/play/listings/it-IT/graphics/phone-screenshots/00.pngbin1054112 -> 0 bytes
-rw-r--r--app/src/main/play/listings/it-IT/graphics/phone-screenshots/01.pngbin950751 -> 0 bytes
-rw-r--r--app/src/main/play/listings/it-IT/graphics/phone-screenshots/02.pngbin573414 -> 0 bytes
-rw-r--r--app/src/main/play/listings/it-IT/graphics/phone-screenshots/03.pngbin635544 -> 0 bytes
-rw-r--r--app/src/main/play/listings/it-IT/graphics/phone-screenshots/04.pngbin792202 -> 0 bytes
-rw-r--r--app/src/main/play/listings/it-IT/graphics/phone-screenshots/05.pngbin945111 -> 0 bytes
-rw-r--r--app/src/main/play/listings/it-IT/short-description.txt1
-rw-r--r--app/src/main/play/listings/it-IT/title.txt1
-rw-r--r--app/src/main/play/listings/iw-IL/full-description.txt31
-rw-r--r--app/src/main/play/listings/iw-IL/short-description.txt1
-rw-r--r--app/src/main/play/listings/iw-IL/title.txt1
-rw-r--r--app/src/main/play/listings/ja-JP/full-description.txt31
-rw-r--r--app/src/main/play/listings/ja-JP/short-description.txt1
-rw-r--r--app/src/main/play/listings/ja-JP/title.txt1
-rw-r--r--app/src/main/play/listings/ko-KR/full-description.txt31
-rw-r--r--app/src/main/play/listings/ko-KR/short-description.txt1
-rw-r--r--app/src/main/play/listings/ko-KR/title.txt1
-rw-r--r--app/src/main/play/listings/lt/full-description.txt31
-rw-r--r--app/src/main/play/listings/lt/short-description.txt1
-rw-r--r--app/src/main/play/listings/lt/title.txt1
-rw-r--r--app/src/main/play/listings/nl-NL/full-description.txt31
-rw-r--r--app/src/main/play/listings/nl-NL/graphics/phone-screenshots/00.pngbin1059430 -> 0 bytes
-rw-r--r--app/src/main/play/listings/nl-NL/graphics/phone-screenshots/01.pngbin963352 -> 0 bytes
-rw-r--r--app/src/main/play/listings/nl-NL/graphics/phone-screenshots/02.pngbin567202 -> 0 bytes
-rw-r--r--app/src/main/play/listings/nl-NL/graphics/phone-screenshots/03.pngbin631105 -> 0 bytes
-rw-r--r--app/src/main/play/listings/nl-NL/graphics/phone-screenshots/04.pngbin789348 -> 0 bytes
-rw-r--r--app/src/main/play/listings/nl-NL/graphics/phone-screenshots/05.pngbin952291 -> 0 bytes
-rw-r--r--app/src/main/play/listings/nl-NL/short-description.txt1
-rw-r--r--app/src/main/play/listings/nl-NL/title.txt1
-rw-r--r--app/src/main/play/listings/pl-PL/full-description.txt31
-rw-r--r--app/src/main/play/listings/pl-PL/short-description.txt1
-rw-r--r--app/src/main/play/listings/pl-PL/title.txt1
-rw-r--r--app/src/main/play/listings/pt-BR/full-description.txt31
-rw-r--r--app/src/main/play/listings/pt-BR/short-description.txt1
-rw-r--r--app/src/main/play/listings/pt-BR/title.txt1
-rw-r--r--app/src/main/play/listings/pt-PT/full-description.txt31
-rw-r--r--app/src/main/play/listings/pt-PT/short-description.txt1
-rw-r--r--app/src/main/play/listings/pt-PT/title.txt1
-rw-r--r--app/src/main/play/listings/ro/full-description.txt31
-rw-r--r--app/src/main/play/listings/ro/short-description.txt1
-rw-r--r--app/src/main/play/listings/ro/title.txt1
-rw-r--r--app/src/main/play/listings/ru-RU/full-description.txt31
-rw-r--r--app/src/main/play/listings/ru-RU/short-description.txt1
-rw-r--r--app/src/main/play/listings/ru-RU/title.txt1
-rw-r--r--app/src/main/play/listings/sk/full-description.txt31
-rw-r--r--app/src/main/play/listings/sk/short-description.txt1
-rw-r--r--app/src/main/play/listings/sk/title.txt1
-rw-r--r--app/src/main/play/listings/sl/full-description.txt31
-rw-r--r--app/src/main/play/listings/sl/short-description.txt1
-rw-r--r--app/src/main/play/listings/sl/title.txt1
-rw-r--r--app/src/main/play/listings/sv-SE/full-description.txt31
-rw-r--r--app/src/main/play/listings/sv-SE/short-description.txt1
-rw-r--r--app/src/main/play/listings/sv-SE/title.txt1
-rw-r--r--app/src/main/play/listings/uk/full-description.txt31
-rw-r--r--app/src/main/play/listings/uk/short-description.txt1
-rw-r--r--app/src/main/play/listings/uk/title.txt1
-rw-r--r--app/src/main/play/listings/zh-CN/full-description.txt31
-rw-r--r--app/src/main/play/listings/zh-CN/short-description.txt1
-rw-r--r--app/src/main/play/listings/zh-CN/title.txt1
-rw-r--r--app/src/main/play/listings/zh-TW/full-description.txt31
-rw-r--r--app/src/main/play/listings/zh-TW/short-description.txt1
-rw-r--r--app/src/main/play/listings/zh-TW/title.txt1
-rw-r--r--app/src/main/play/release-notes/en-US/default.txt7
-rw-r--r--app/src/main/res/layout/authentication_dialog.xml82
-rw-r--r--app/src/main/res/layout/dialog_switch_preference.xml2
-rw-r--r--app/src/main/res/layout/downloadlog_item.xml11
-rw-r--r--app/src/main/res/layout/edit_tags_dialog.xml2
-rw-r--r--app/src/main/res/layout/feeditemlist_header.xml2
-rw-r--r--app/src/main/res/layout/playback_speed_feed_setting_dialog.xml6
-rw-r--r--app/src/main/res/layout/proxy_settings.xml6
-rw-r--r--app/src/main/res/layout/swipeactions_dialog.xml2
-rw-r--r--app/src/play/java/de/danoeh/antennapod/dialog/RatingDialog.java2
-rw-r--r--build.gradle50
-rw-r--r--common.gradle59
-rw-r--r--config/checkstyle/checkstyle.xml8
-rw-r--r--config/spotbugs/exclude.xml53
-rw-r--r--core/build.gradle16
-rw-r--r--core/src/free/java/de/danoeh/antennapod/core/service/playback/WearMediaSession.java17
-rw-r--r--core/src/main/AndroidManifest.xml1
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java31
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/export/CommonSymbols.java25
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/export/ExportWriter.java31
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/LocalFeedUpdater.java7
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/util/PlaybackSpeedUtils.java22
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java22
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java16
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequestCreator.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/HttpCredentialEncoder.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java8
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/handler/MediaDownloadedHandler.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java99
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java23
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java59
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/WearMediaSession.java (renamed from core/src/play/java/de/danoeh/antennapod/core/service/playback/WearMediaSession.java)7
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java36
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java48
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/NavDrawerData.java12
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/DateFormatter.java7
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/ReleaseScheduleGuesser.java219
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/download/ConnectionStateMonitor.java41
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/download/NetworkConnectionChangeHandler.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/MediaPlayerError.java36
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java12
-rw-r--r--core/src/main/res/drawable-nodpi/teaser.pngbin168091 -> 0 bytes
-rw-r--r--core/src/main/res/drawable-nodpi/teaser.webpbin0 -> 21054 bytes
-rw-r--r--core/src/main/res/drawable/ic_eye.xml5
-rw-r--r--core/src/main/res/values/arrays.xml5
-rw-r--r--core/src/test/java/android/text/TextUtils.java1
-rw-r--r--core/src/test/java/de/danoeh/antennapod/core/storage/DbReaderTest.java5
-rw-r--r--core/src/test/java/de/danoeh/antennapod/core/storage/DbTasksTest.java21
-rw-r--r--core/src/test/java/de/danoeh/antennapod/core/storage/ItemEnqueuePositionCalculatorTest.java3
-rw-r--r--core/src/test/java/de/danoeh/antennapod/core/storage/mapper/FeedCursorMapperTest.java2
-rw-r--r--core/src/test/java/de/danoeh/antennapod/core/util/ReleaseScheduleGuesserRealWorldTest.java125
-rw-r--r--core/src/test/java/de/danoeh/antennapod/core/util/ReleaseScheduleGuesserTest.java172
-rw-r--r--core/src/test/resources/release_dates.csv150
-rwxr-xr-xcore/src/test/resources/release_dates.sh10
-rw-r--r--event/src/main/java/de/danoeh/antennapod/event/settings/SpeedPresetChangedEvent.java10
-rw-r--r--gradle.properties4
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin62076 -> 43462 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties3
-rwxr-xr-xgradlew22
-rw-r--r--gradlew.bat20
-rw-r--r--model/src/main/java/de/danoeh/antennapod/model/download/DownloadResult.java15
-rw-r--r--model/src/main/java/de/danoeh/antennapod/model/feed/Chapter.java16
-rw-r--r--model/src/main/java/de/danoeh/antennapod/model/feed/Feed.java104
-rw-r--r--model/src/main/java/de/danoeh/antennapod/model/feed/FeedComponent.java65
-rw-r--r--model/src/main/java/de/danoeh/antennapod/model/feed/FeedFile.java107
-rw-r--r--model/src/main/java/de/danoeh/antennapod/model/feed/FeedItem.java21
-rw-r--r--model/src/main/java/de/danoeh/antennapod/model/feed/FeedMedia.java143
-rw-r--r--model/src/main/java/de/danoeh/antennapod/model/feed/FeedPreferences.java35
-rw-r--r--model/src/main/java/de/danoeh/antennapod/model/feed/SortOrder.java8
-rw-r--r--net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/DownloadRequest.java4
-rw-r--r--net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/gpoddernet/GpodnetService.java40
-rw-r--r--net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/nextcloud/NextcloudLoginFlow.java2
-rw-r--r--net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/nextcloud/NextcloudSyncService.java4
-rw-r--r--parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Atom.java22
-rw-r--r--parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/DublinCore.java4
-rw-r--r--playback/base/src/main/java/de/danoeh/antennapod/playback/base/PlaybackServiceMediaPlayer.java2
-rw-r--r--playback/cast/build.gradle2
-rw-r--r--playback/cast/src/play/java/de/danoeh/antennapod/playback/cast/CastPsmp.java6
-rw-r--r--scripts/createScreenshots.sh126
-rw-r--r--settings.gradle18
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBUpgrader.java4
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java8
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedPreferencesCursorMapper.java5
-rw-r--r--storage/importexport/README.md3
-rw-r--r--storage/importexport/build.gradle21
-rw-r--r--storage/importexport/src/main/assets/html-export-favorites-item-template.html (renamed from core/src/main/assets/html-export-favorites-item-template.html)0
-rw-r--r--storage/importexport/src/main/assets/html-export-feed-template.html (renamed from core/src/main/assets/html-export-feed-template.html)0
-rw-r--r--storage/importexport/src/main/assets/html-export-template.html (renamed from core/src/main/assets/html-export-template.html)1
-rw-r--r--storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/DatabaseExporter.java (renamed from core/src/main/java/de/danoeh/antennapod/core/storage/DatabaseExporter.java)3
-rw-r--r--storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/FavoritesWriter.java (renamed from core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java)24
-rw-r--r--storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/HtmlWriter.java (renamed from core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlWriter.java)13
-rw-r--r--storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlElement.java (renamed from core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlElement.java)2
-rw-r--r--storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlReader.java (renamed from core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlReader.java)5
-rw-r--r--storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlSymbols.java (renamed from core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlSymbols.java)11
-rw-r--r--storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlWriter.java (renamed from core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlWriter.java)20
-rw-r--r--storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java89
-rw-r--r--ui/common/src/main/java/de/danoeh/antennapod/ui/common/PagedToolbarFragment.java18
-rw-r--r--ui/common/src/main/java/de/danoeh/antennapod/ui/common/TriangleLabelView.java215
-rw-r--r--ui/common/src/main/res/values/attrs.xml18
-rw-r--r--ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/EchoActivity.java2
-rw-r--r--ui/glide/src/main/java/de/danoeh/antennapod/ui/glide/ApOkHttpUrlLoader.java2
-rw-r--r--ui/glide/src/main/java/de/danoeh/antennapod/ui/glide/FastBlurTransformation.java2
-rw-r--r--ui/i18n/src/main/res/values/strings.xml34
-rw-r--r--ui/png-icons/src/main/res/drawable/ic_notification_sleep.xml5
-rw-r--r--ui/png-icons/src/main/res/drawable/ic_notification_sleep_off.xml5
-rw-r--r--ui/statistics/build.gradle2
-rw-r--r--ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/feed/FeedStatisticsFragment.java92
-rw-r--r--ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/years/BarChartView.java12
-rw-r--r--ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/years/YearStatisticsListAdapter.java30
-rw-r--r--ui/statistics/src/main/res/layout/feed_statistics.xml41
306 files changed, 2247 insertions, 2884 deletions
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
index 8853e82e2..4729dec3f 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -1,5 +1,6 @@
name: Feature request
description: Request a new feature or enhancement
+labels: ["Needs: Triage", "Type: Feature request"]
body:
- type: checkboxes
id: checklist
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index f9fea783a..ef44d874d 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1 +1,14 @@
-<!-- Please make sure that you have read our contribution guidelines: https://github.com/AntennaPod/AntennaPod/blob/develop/CONTRIBUTING.md#submit-a-pull-request -->
+### Description
+
+
+### Checklist
+<!--
+ To help us keep the issue tracker clean and work as efficient as possible,
+ please make sure that you have done all of the following.
+ You can tick the boxes below by placing an x inside the brackets like this: [x]
+-->
+- [ ] I have read the contribution guidelines: https://github.com/AntennaPod/AntennaPod/blob/develop/CONTRIBUTING.md#submit-a-pull-request
+- [ ] I have performed a self-review of my code
+- [ ] My code follows the style guidelines of the AntennaPod project: https://github.com/AntennaPod/AntennaPod/wiki/Code-style
+- [ ] I have mentioned the corresponding issue and the relevant keyword (e.g., "Closes: #xy") in the description (see https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)
+- [ ] If it is a core feature, I have added automated tests
diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml
index 4b7c49333..9dbfdcf1a 100644
--- a/.github/workflows/checks.yml
+++ b/.github/workflows/checks.yml
@@ -2,9 +2,9 @@ name: Checks
on:
pull_request:
- types: [opened, synchronize, reopened]
+ types: [ opened, synchronize, reopened ]
push:
- branches: [master, develop]
+ branches: [ master, develop ]
jobs:
code-style:
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Checkstyle
@@ -23,7 +23,7 @@ jobs:
id: vars
run: |
git fetch origin develop
- echo "::set-output name=branchBaseCommit::$(git merge-base origin/develop HEAD)"
+ echo "branchBaseCommit=$(git merge-base origin/develop HEAD)" >> $GITHUB_OUTPUT
- name: Diff-Checkstyle
run: |
curl -s -L https://github.com/yangziwen/diff-check/releases/download/0.0.7/diff-checkstyle.jar > diff-checkstyle.jar
@@ -40,8 +40,8 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- - uses: actions/checkout@v3
- - uses: gradle/wrapper-validation-action@v1
+ - uses: actions/checkout@v4
+ - uses: gradle/wrapper-validation-action@v2
static-analysis:
name: "Static Code Analysis"
@@ -49,9 +49,14 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
+ - name: Set up JDK 17
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'temurin'
+ java-version: '17'
- name: Cache Gradle
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: |
~/.gradle/caches
@@ -60,7 +65,7 @@ jobs:
- name: Lint :app module recursively
run: ./gradlew :app:lintPlayRelease
- name: SpotBugs
- run: ./gradlew spotbugsPlayDebug spotbugsDebug 2>&1 | grep -i "spotbugs"
+ run: ./gradlew spotbugsPlayDebug spotbugsDebug
unit-test:
name: "Unit Test: ${{ matrix.variant }}"
@@ -83,9 +88,14 @@ jobs:
execute-tests: false
upload-artifact: false
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
+ - name: Set up JDK 17
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'temurin'
+ java-version: '17'
- name: Cache Gradle
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: |
~/.gradle/caches
@@ -98,7 +108,7 @@ jobs:
- name: Test
if: matrix.execute-tests == true
run: ./gradlew test${{ matrix.variant }}UnitTest test${{ matrix.base-variant }}UnitTest
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
if: matrix.upload-artifact == true
with:
name: app-play-debug.apk
@@ -112,14 +122,14 @@ jobs:
env:
api-level: 30
steps:
- - uses: actions/checkout@v3
- - name: Set up JDK 11
- uses: actions/setup-java@v3
+ - uses: actions/checkout@v4
+ - name: Set up JDK 17
+ uses: actions/setup-java@v4
with:
distribution: 'temurin'
- java-version: '11'
+ java-version: '17'
- name: Cache Gradle
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: |
~/.gradle/caches
@@ -137,7 +147,7 @@ jobs:
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
script: zsh .github/workflows/runEmulatorTests.sh
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
if: failure()
with:
name: test-report
diff --git a/.github/workflows/close-if-no-reply.yml b/.github/workflows/close-if-no-reply.yml
index 1c02efce0..16b964b60 100644
--- a/.github/workflows/close-if-no-reply.yml
+++ b/.github/workflows/close-if-no-reply.yml
@@ -15,13 +15,13 @@ jobs:
with:
days-before-stale: 7
days-before-close: 7
- only-labels: 'Awaiting reply'
- stale-issue-label: 'Still awaiting reply'
- stale-pr-label: 'Still awaiting reply'
+ only-labels: 'Needs: Reply'
+ stale-issue-label: 'Needs: Reply still'
+ stale-pr-label: 'Needs: Reply still'
stale-issue-message: "This issue will be closed when we don't get a reply within 7 days."
stale-pr-message: "This PR will be closed when we don't get a reply within 7 days."
- labels-to-remove-when-unstale: 'Awaiting reply'
- close-issue-label: "Close reason: no reply"
- close-pr-label: "Close reason: no reply"
+ labels-to-remove-when-unstale: 'Needs: Reply'
+ close-issue-label: "Close reason: No reply"
+ close-pr-label: "Close reason: No reply"
close-issue-message: "This issue was closed because we didn't get a reply for 14 days."
close-pr-message: "This PR was closed because we didn't get a reply for 14 days."
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 000000000..7829a701d
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,4 @@
+[submodule "app/src/main/play"]
+ path = app/src/main/play
+ url = https://github.com/AntennaPod/StoreMetadata.git
+ branch = main
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 0017c897d..201e98545 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -28,25 +28,40 @@ If you would like to translate the app into another language or improve an exist
Submit a pull request
---------------------
-- If you want to work on a feature that has been requested or fix a bug that has been reported on the "issues" page, add a comment to it so that other people know that you are working on it.
-- Fork the repository.
-- Almost all changes of AntennaPod are done on the `develop` branch. If a new version of AntennaPod is released, the `develop` branch is merged into `master`. As a result, the `master` branch probably doesn't contain the latest changes when you are reading this. Please make sure that you are branching from `develop`! Otherwise, there might be a lot of merge-conflicts when merging your changes into `develop` and therefore it might take longer to review your pull-request. Exceptions are urgent issues that need to be fixed in the production version.
-- If your pull request fixes a bug that has been reported or implements a feature that has been requested in another issue, try to mention it in the message, so that it can be closed once your pull request has been merged. If you use special keywords in the [commit comment](https://help.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue) or [pull request text](https://github.blog/2013-05-14-closing-issues-via-pull-requests/), GitHub will close the issue(s) automatically.
-- If possible, add unit tests for your pull request and make sure that they pass.
-- Please do not upgrade dependencies or build tools unless you have a good reason for it. Doing so can easily introduce bugs that are hard to track down.
-- If you plan to do a change that touches many files (10+), please ask beforehand. This usually causes merge conflicts for other developers.
-- Please follow our code style. You can use Checkstyle within Android Studio using our [configuration file](https://github.com/AntennaPod/AntennaPod/blob/develop/config/checkstyle/checkstyle-new-code.xml).
-- Please only change the English string resources. Translations are handled on [Transifex](https://www.transifex.com/antennapod/antennapod/).
+- Before you work on the code
+ - Make sure that there is an issue *without* the `Needs: Triage` or `Needs: Decision` label for the feature you want to implement or bug you want to fix.
+ - Add a comment to the issue so that other people know that you are working on it.
+ - You don't need to ask for permission to work on something, just indicate that you are doing so.
+ - If you want to discuss the approach to take, feel free to ask in the issue or join a [community call](https://antennapod.org/events/community-meeting).
+- Fork the repository
+- Create a new branch for your contribution
+ - This makes opening possible additional pull requests easier.
+ - As a base, use the `develop` branch.
+ - Almost all changes of AntennaPod are done on the `develop` branch. If a new version of AntennaPod is released, the `develop` branch is merged into `master`. As a result, the `master` branch probably doesn't contain the latest changes when you are reading this. Otherwise, there might be a lot of merge-conflicts when merging your changes into `develop` and therefore it might take longer to review your pull-request.
+- Get coding :)
+ - If possible, add unit tests for your pull request and make sure that they pass.
+ - Please do not upgrade dependencies or build tools unless you have a good reason for it. Doing so can easily introduce bugs that are hard to track down.
+ - Please follow our code style. You can use Checkstyle within Android Studio using our [configuration file](https://github.com/AntennaPod/AntennaPod/blob/develop/config/checkstyle/checkstyle-new-code.xml).
+ - Please only change the English string resources. Translations are handled on [Transifex](https://www.transifex.com/antennapod/antennapod/).
+- Open the PR
+ - Mention the corresponding issue in the pull request text, so that it can be closed once your pull request has been merged. If you use [special keywords](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue), GitHub will close the issue(s) automatically.
+
Building From Source
--------------------------
1. Fork this repository
1. Download Android Studio
-1. In Android Studio
- 1. File » New » Project from version control
- 2. Enter the remote url of the forked repo
- 2. Wait for a long time until all progress bars go away
- 3. Press the Play button
+1. Download AntennaPod
+ 1. Option A: Using the git command line (recommended)
+ 1. Use `git clone <url>` with the remote url of your forked repo.
+ The AntennaPod repo contains a large submodule with app store metadata like screenshots.
+ You **do not need that** for normal development.
+ 1. In Android Studio: File » New » Project from existing sources
+ 1. Option B: From Android Studio
+ 1. File » New » Project from version control
+ 1. Enter the remote url of the forked repo
+1. Wait for a long time until all progress bars go away
+1. Press the Play button
Testing and Verifying
--------------------------
diff --git a/README.md b/README.md
index ab26482ea..91bcb2ee9 100644
--- a/README.md
+++ b/README.md
@@ -8,14 +8,14 @@ This is the official repository of AntennaPod, the easy-to-use, flexible and ope
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Get it on F-Droid"
height="70">](https://f-droid.org/app/de.danoeh.antennapod)
-
-<img src="https://raw.githubusercontent.com/AntennaPod/AntennaPod/develop/app/src/main/play/listings/en-US/graphics/phone-screenshots/00.png" alt="Screenshot 0" height="200"> <img src="https://raw.githubusercontent.com/AntennaPod/AntennaPod/develop/app/src/main/play/listings/en-US/graphics/phone-screenshots/01.png" alt="Screenshot 1" height="200"> <img src="https://raw.githubusercontent.com/AntennaPod/AntennaPod/develop/app/src/main/play/listings/en-US/graphics/phone-screenshots/02.png" alt="Screenshot 2" height="200"> <img src="https://raw.githubusercontent.com/AntennaPod/AntennaPod/develop/app/src/main/play/listings/en-US/graphics/phone-screenshots/03.png" alt="Screenshot 3" height="200"> <img src="https://raw.githubusercontent.com/AntennaPod/AntennaPod/develop/app/src/main/play/listings/en-US/graphics/phone-screenshots/04.png" alt="Screenshot 4" height="200"> <img src="https://raw.githubusercontent.com/AntennaPod/AntennaPod/develop/app/src/main/play/listings/en-US/graphics/phone-screenshots/05.png" alt="Screenshot 5" height="200">
+
+<img src="https://raw.githubusercontent.com/AntennaPod/StoreMetadata/main/listings/en-US/graphics/phone-screenshots/00.png" alt="Screenshot 0" height="200"> <img src="https://raw.githubusercontent.com/AntennaPod/StoreMetadata/main/listings/en-US/graphics/phone-screenshots/01.png" alt="Screenshot 1" height="200"> <img src="https://raw.githubusercontent.com/AntennaPod/StoreMetadata/main/listings/en-US/graphics/phone-screenshots/02.png" alt="Screenshot 2" height="200"> <img src="https://raw.githubusercontent.com/AntennaPod/StoreMetadata/main/listings/en-US/graphics/phone-screenshots/03.png" alt="Screenshot 3" height="200"> <img src="https://raw.githubusercontent.com/AntennaPod/StoreMetadata/main/listings/en-US/graphics/phone-screenshots/04.png" alt="Screenshot 4" height="200"> <img src="https://raw.githubusercontent.com/AntennaPod/StoreMetadata/main/listings/en-US/graphics/phone-screenshots/05.png" alt="Screenshot 5" height="200">
## Feedback
You can use the [AntennaPod Forum](https://forum.antennapod.org/) for discussions about the app or just podcasting in general.
-Bug reports and feature requests can be submitted [here](https://github.com/AntennaPod/AntennaPod/issues) (please read the [instructions](https://github.com/AntennaPod/AntennaPod/blob/master/CONTRIBUTING.md) on how to report a bug and how to submit a feature request first!).
+Bug reports and feature requests can be submitted [here](https://github.com/AntennaPod/AntennaPod/issues) (please read the [instructions](https://github.com/AntennaPod/AntennaPod/blob/develop/CONTRIBUTING.md) on how to report a bug and how to submit a feature request first!).
We also hold regular community calls to discuss anything AntennaPod-related. [Come join the next call](https://forum.antennapod.org/t/monthly-community-call/1869)!
@@ -27,10 +27,11 @@ AntennaPod has many users and we don't want them to run into trouble when we add
AntennaPod is licensed under the GNU General Public License (GPL-3.0). You can find the license text in the LICENSE file.
## Translating AntennaPod
+
If you want to translate AntennaPod into another language, you can visit the [Transifex project page](https://www.transifex.com/antennapod/antennapod/).
## Building AntennaPod
-You can build AntennaPod just like any other Android project. On Android Studio, simply select `File` » `New` » `Project from version control` and paste AntennaPod's GitHub URL.
+You can build AntennaPod just like any other Android project. Refer to the [instructions](https://github.com/AntennaPod/AntennaPod/blob/develop/CONTRIBUTING.md) for more details.
diff --git a/app/build.gradle b/app/build.gradle
index 0dfa10e52..d0958cd17 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,6 +1,6 @@
plugins {
id('com.android.application')
- id('com.github.triplet.play') version '3.8.3' apply false
+ id('com.github.triplet.play') version '3.9.0' apply false
}
apply from: "../common.gradle"
apply from: "../playFlavor.gradle"
@@ -69,7 +69,7 @@ android {
}
androidResources {
- additionalParameters "--no-version-vectors"
+ additionalParameters += ["--no-version-vectors"]
}
}
@@ -86,6 +86,7 @@ dependencies {
implementation project(':playback:base')
implementation project(':playback:cast')
implementation project(':storage:database')
+ implementation project(':storage:importexport')
implementation project(':storage:preferences')
implementation project(':ui:app-start-intent')
implementation project(':ui:common')
@@ -114,23 +115,18 @@ dependencies {
implementation "com.github.bumptech.glide:glide:$glideVersion"
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
implementation "com.squareup.okhttp3:okhttp-urlconnection:$okhttpVersion"
- implementation "com.squareup.okio:okio:$okioVersion"
implementation "org.greenrobot:eventbus:$eventbusVersion"
annotationProcessor "org.greenrobot:eventbus-annotation-processor:$eventbusVersion"
implementation "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
- implementation "com.joanzapata.iconify:android-iconify-fontawesome:$iconifyVersion"
- implementation "com.joanzapata.iconify:android-iconify-material:$iconifyVersion"
implementation 'com.leinardi.android:speed-dial:3.2.0'
implementation 'com.github.ByteHamster:SearchPreference:v2.5.0'
implementation 'com.github.skydoves:balloon:1.5.3'
implementation 'com.github.xabaras:RecyclerViewSwipeDecorator:1.3'
- implementation "com.annimon:stream:$annimonStreamVersion"
// Non-free dependencies:
- playImplementation 'com.google.android.play:core:1.8.0'
- compileOnly "com.google.android.wearable:wearable:$wearableSupportVersion"
+ playImplementation "com.google.android.play:review:2.0.1"
androidTestImplementation "org.awaitility:awaitility:$awaitilityVersion"
androidTestImplementation 'com.nanohttpd:nanohttpd:2.1.1'
@@ -150,7 +146,7 @@ if (project.hasProperty("antennaPodPlayPublisherCredentials")) {
}
}
-task copyLicense(type: Copy) {
+tasks.register('copyLicense', Copy) {
from "../LICENSE"
into "src/main/assets/"
rename { String fileName ->
diff --git a/app/proguard.cfg b/app/proguard.cfg
index 57c5ca9dc..1fd4cc501 100644
--- a/app/proguard.cfg
+++ b/app/proguard.cfg
@@ -28,10 +28,6 @@
public *;
}
-# for okhttp
--dontwarn okhttp3.**
--dontwarn okio.**
-
# android-iconify
-keep class com.joanzapata.** { *; }
diff --git a/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java b/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java
index aa55a1e59..5cdedc1ac 100644
--- a/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java
@@ -7,7 +7,7 @@ import android.util.Log;
import java.io.File;
import java.io.IOException;
-import de.danoeh.antennapod.model.feed.FeedFile;
+import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.storage.preferences.UserPreferences;
import de.danoeh.antennapod.net.download.serviceinterface.DownloadRequest;
import de.danoeh.antennapod.model.download.DownloadResult;
@@ -60,8 +60,8 @@ public class HttpDownloaderTest {
urlAuth = httpServer.getBaseUrl() + "/basic-auth/user/passwd";
}
- private FeedFileImpl setupFeedFile(String downloadUrl, String title, boolean deleteExisting) {
- FeedFileImpl feedfile = new FeedFileImpl(downloadUrl);
+ private Feed setupFeedFile(String downloadUrl, String title, boolean deleteExisting) {
+ Feed feedfile = new Feed(downloadUrl, "");
String fileUrl = new File(destDir, title).getAbsolutePath();
File file = new File(fileUrl);
if (deleteExisting) {
@@ -77,8 +77,8 @@ public class HttpDownloaderTest {
private Downloader download(String url, String title, boolean expectedResult, boolean deleteExisting,
String username, String password) {
- FeedFile feedFile = setupFeedFile(url, title, deleteExisting);
- DownloadRequest request = new DownloadRequest(feedFile.getFile_url(), url, title, 0, feedFile.getTypeAsInt(),
+ Feed feedFile = setupFeedFile(url, title, deleteExisting);
+ DownloadRequest request = new DownloadRequest(feedFile.getFile_url(), url, title, 0, Feed.FEEDFILETYPE_FEED,
username, password, null, false);
Downloader downloader = new HttpDownloader(request);
downloader.call();
@@ -113,9 +113,9 @@ public class HttpDownloaderTest {
@Test
public void testCancel() {
final String url = httpServer.getBaseUrl() + "/delay/3";
- FeedFileImpl feedFile = setupFeedFile(url, "delay", true);
+ Feed feedFile = setupFeedFile(url, "delay", true);
final Downloader downloader = new HttpDownloader(new DownloadRequest(feedFile.getFile_url(), url, "delay", 0,
- feedFile.getTypeAsInt(), null, null, null, false));
+ Feed.FEEDFILETYPE_FEED, null, null, null, false));
Thread t = new Thread() {
@Override
public void run() {
@@ -159,28 +159,4 @@ public class HttpDownloaderTest {
Downloader downloader = download(urlAuth, "testAuthSuccess", false, true, "user", "Wrong passwd");
assertEquals(DownloadError.ERROR_UNAUTHORIZED, downloader.getResult().getReason());
}
-
- /* TODO: replace with smaller test file
- public void testUrlWithSpaces() {
- download("http://acedl.noxsolutions.com/ace/Don't Call Salman Rushdie Sneezy in Finland.mp3", "testUrlWithSpaces", true);
- }
- */
-
- private static class FeedFileImpl extends FeedFile {
- public FeedFileImpl(String download_url) {
- super(null, download_url, false);
- }
-
-
- @Override
- public String getHumanReadableIdentifier() {
- return download_url;
- }
-
- @Override
- public int getTypeAsInt() {
- return 0;
- }
- }
-
}
diff --git a/app/src/androidTest/java/de/test/antennapod/util/event/FeedItemEventListener.java b/app/src/androidTest/java/de/test/antennapod/util/event/FeedItemEventListener.java
deleted file mode 100644
index 7e8fc1205..000000000
--- a/app/src/androidTest/java/de/test/antennapod/util/event/FeedItemEventListener.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package de.test.antennapod.util.event;
-
-import androidx.annotation.NonNull;
-
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import de.danoeh.antennapod.event.FeedItemEvent;
-import io.reactivex.functions.Consumer;
-
-/**
- * Test helpers to listen {@link FeedItemEvent} and handle them accordingly
- *
- */
-public class FeedItemEventListener {
- private final List<FeedItemEvent> events = new ArrayList<>();
-
- /**
- * Provides an listener subscribing to {@link FeedItemEvent} that the callers can use
- *
- * Note: it uses RxJava's version of {@link Consumer} because it allows exceptions to be thrown.
- */
- public static void withFeedItemEventListener(@NonNull Consumer<FeedItemEventListener> consumer)
- throws Exception {
- FeedItemEventListener feedItemEventListener = new FeedItemEventListener();
- try {
- EventBus.getDefault().register(feedItemEventListener);
- consumer.accept(feedItemEventListener);
- } finally {
- EventBus.getDefault().unregister(feedItemEventListener);
- }
- }
-
- @Subscribe
- public void onEvent(FeedItemEvent event) {
- events.add(event);
- }
-
- @NonNull
- public List<? extends FeedItemEvent> getEvents() {
- return events;
- }
-}
diff --git a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java
index 6b85f3bf8..ec4a58e33 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java
@@ -6,13 +6,15 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.OutputStream;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Date;
+import java.util.Locale;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedFunding;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.parser.feed.namespace.PodcastIndex;
-import de.danoeh.antennapod.core.util.DateFormatter;
/**
* Creates RSS 2.0 feeds. See FeedGenerator for more information.
@@ -98,7 +100,7 @@ public class Rss2Generator implements FeedGenerator {
}
if (item.getPubDate() != null) {
xml.startTag(null, "pubDate");
- xml.text(DateFormatter.formatRfc822Date(item.getPubDate()));
+ xml.text(formatRfc822Date(item.getPubDate()));
xml.endTag(null, "pubDate");
}
if ((flags & FEATURE_WRITE_GUID) != 0) {
@@ -132,4 +134,9 @@ public class Rss2Generator implements FeedGenerator {
xml.endDocument();
}
+
+ private static String formatRfc822Date(Date date) {
+ SimpleDateFormat format = new SimpleDateFormat("dd MMM yy HH:mm:ss Z", Locale.US);
+ return format.format(date);
+ }
}
diff --git a/app/src/main/assets/LICENSE_ANDROID_ICONIFY.txt b/app/src/main/assets/LICENSE_ANDROID_ICONIFY.txt
deleted file mode 100644
index 954402c93..000000000
--- a/app/src/main/assets/LICENSE_ANDROID_ICONIFY.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-Copyright 2015 Joan Zapata
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-It uses FontAwesome font, licensed under OFL 1.1, which is compatible
-with this library's license.
-
- http://scripts.sil.org/cms/scripts/render_download.php?format=file&media_id=OFL_plaintext&filename=OFL.txt
diff --git a/app/src/main/assets/LICENSE_TRIANGLE_LABEL_VIEW.txt b/app/src/main/assets/LICENSE_TRIANGLE_LABEL_VIEW.txt
deleted file mode 100644
index de9a1f228..000000000
--- a/app/src/main/assets/LICENSE_TRIANGLE_LABEL_VIEW.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-Copyright (C) 2016 Shota Saito
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License. \ No newline at end of file
diff --git a/app/src/main/assets/licenses.xml b/app/src/main/assets/licenses.xml
index de06d42a1..e6745e4f5 100644
--- a/app/src/main/assets/licenses.xml
+++ b/app/src/main/assets/licenses.xml
@@ -61,24 +61,12 @@
license="Simplified BSD"
licenseText="LICENSE_GLIDE.txt" />
<library
- name="Iconify"
- author="Joan Zapata"
- website="https://github.com/JoanZapata/android-iconify"
- license="Apache 2.0"
- licenseText="LICENSE_ANDROID_ICONIFY.txt" />
- <library
name="jsoup"
author="Jonathan Hedley"
website="https://jsoup.org/"
license="MIT"
licenseText="LICENSE_JSOUP.txt" />
<library
- name="Lightweight-Stream-API"
- author="Victor Melnik"
- website="https://github.com/aNNiMON/Lightweight-Stream-API"
- license="Apache 2.0"
- licenseText="LICENSE_APACHE-2.0.txt" />
- <library
name="Material Components for Android"
author="Google"
website="https://github.com/material-components/material-components-android"
@@ -103,12 +91,6 @@
license="Apache 2.0"
licenseText="LICENSE_OKHTTP.txt" />
<library
- name="Okio"
- author="Square"
- website="https://github.com/square/okio"
- license="Apache 2.0"
- licenseText="LICENSE_APACHE-2.0.txt" />
- <library
name="RecyclerViewSwipeDecorator"
author="Paolo Montalto"
website="https://github.com/xabaras/RecyclerViewSwipeDecorator"
@@ -138,10 +120,4 @@
website="https://github.com/kikoso/android-stackblur"
license="Apache 2.0"
licenseText="LICENSE_APACHE-2.0.txt" />
- <library
- name="Triangle Label View"
- author="Shota Saito"
- website="https://github.com/shts/TriangleLabelView"
- license="Apache 2.0"
- licenseText="LICENSE_TRIANGLE_LABEL_VIEW.txt" />
</libraries>
diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
index 28b47c570..8e840885b 100644
--- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
+++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
@@ -6,9 +6,6 @@ import android.content.Intent;
import android.os.StrictMode;
import com.google.android.material.color.DynamicColors;
-import com.joanzapata.iconify.Iconify;
-import com.joanzapata.iconify.fonts.FontAwesomeModule;
-import com.joanzapata.iconify.fonts.MaterialModule;
import de.danoeh.antennapod.activity.SplashActivity;
import de.danoeh.antennapod.config.ApplicationCallbacksImpl;
@@ -55,9 +52,6 @@ public class PodcastApp extends Application {
ClientConfigurator.initialize(this);
PreferenceUpgrader.checkUpgrades(this);
- Iconify.with(new FontAwesomeModule());
- Iconify.with(new MaterialModule());
-
SPAUtil.sendSPAppsQueryFeedsIntent(this);
EventBus.builder()
.addIndex(new ApEventBusIndex())
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
index 1baa90d28..b4d45b262 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -241,8 +241,9 @@ public class MainActivity extends CastEnabledActivity {
outState.putInt(KEY_GENERATED_VIEW_ID, View.generateViewId());
}
- private final BottomSheetBehavior.BottomSheetCallback bottomSheetCallback =
- new BottomSheetBehavior.BottomSheetCallback() {
+ private final BottomSheetBehavior.BottomSheetCallback bottomSheetCallback = new AntennaPodBottomSheetCallback();
+
+ private class AntennaPodBottomSheetCallback extends BottomSheetBehavior.BottomSheetCallback {
@Override
public void onStateChanged(@NonNull View view, int state) {
if (state == BottomSheetBehavior.STATE_COLLAPSED) {
@@ -266,7 +267,7 @@ public class MainActivity extends CastEnabledActivity {
audioPlayer.fadePlayerToToolbar(slideOffset);
}
- };
+ }
public void setupToolbarToggle(@NonNull MaterialToolbar toolbar, boolean displayUpArrow) {
if (drawerLayout != null) { // Tablet layout does not have a drawer
@@ -290,7 +291,7 @@ public class MainActivity extends CastEnabledActivity {
@Override
protected void onDestroy() {
super.onDestroy();
- if (drawerLayout != null) {
+ if (drawerLayout != null && drawerToggle != null) {
drawerLayout.removeDrawerListener(drawerToggle);
}
}
@@ -551,7 +552,7 @@ public class MainActivity extends CastEnabledActivity {
@Override
public void onBackPressed() {
- if (isDrawerOpen()) {
+ if (isDrawerOpen() && drawerLayout != null) {
drawerLayout.closeDrawer(navDrawer);
} else if (sheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) {
sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
index 3f1c17cdc..caafe989d 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
@@ -26,14 +26,14 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.export.opml.OpmlElement;
-import de.danoeh.antennapod.core.export.opml.OpmlReader;
import de.danoeh.antennapod.core.preferences.ThemeSwitcher;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import de.danoeh.antennapod.databinding.OpmlSelectionBinding;
import de.danoeh.antennapod.model.feed.Feed;
+import de.danoeh.antennapod.storage.importexport.OpmlElement;
+import de.danoeh.antennapod.storage.importexport.OpmlReader;
import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java b/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
index d5c67c675..c87228cdd 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
@@ -11,7 +11,6 @@ import com.bumptech.glide.RequestBuilder;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.CustomViewTarget;
import com.bumptech.glide.request.transition.Transition;
-import de.danoeh.antennapod.activity.MainActivity;
import java.lang.ref.WeakReference;
@@ -21,11 +20,9 @@ public class CoverLoader {
private String fallbackUri;
private ImageView imgvCover;
private boolean textAndImageCombined;
- private MainActivity activity;
private TextView fallbackTitle;
- public CoverLoader(MainActivity activity) {
- this.activity = activity;
+ public CoverLoader() {
}
public CoverLoader withUri(String uri) {
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
index 08d7cbefd..3dad75e59 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
@@ -17,7 +17,6 @@ import de.danoeh.antennapod.model.download.DownloadError;
import de.danoeh.antennapod.model.download.DownloadResult;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedMedia;
-import de.danoeh.antennapod.ui.common.ThemeUtils;
import de.danoeh.antennapod.view.viewholder.DownloadLogItemViewHolder;
import java.util.ArrayList;
@@ -74,19 +73,16 @@ public class DownloadLogAdapter extends BaseAdapter {
}
if (status.isSuccessful()) {
- holder.icon.setTextColor(ThemeUtils.getColorFromAttr(context, R.attr.icon_green));
- holder.icon.setText("{fa-check-circle}");
+ holder.icon.setImageResource(R.drawable.ic_check);
holder.icon.setContentDescription(context.getString(R.string.download_successful));
holder.secondaryActionButton.setVisibility(View.INVISIBLE);
holder.reason.setVisibility(View.GONE);
holder.tapForDetails.setVisibility(View.GONE);
} else {
if (status.getReason() == DownloadError.ERROR_PARSER_EXCEPTION_DUPLICATE) {
- holder.icon.setTextColor(ThemeUtils.getColorFromAttr(context, R.attr.icon_yellow));
- holder.icon.setText("{fa-exclamation-circle}");
+ holder.icon.setImageResource(R.drawable.ic_info);
} else {
- holder.icon.setTextColor(ThemeUtils.getColorFromAttr(context, R.attr.icon_red));
- holder.icon.setText("{fa-times-circle}");
+ holder.icon.setImageResource(R.drawable.ic_error);
}
holder.icon.setContentDescription(context.getString(R.string.error_label));
holder.reason.setText(DownloadErrorLabel.from(status.getReason()));
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
index a304ead3c..176828308 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
@@ -341,7 +341,7 @@ public class NavListAdapter extends RecyclerView.Adapter<NavListAdapter.Holder>
if (context == null) {
return;
}
- if (tag.isOpen) {
+ if (tag.isOpen()) {
holder.count.setVisibility(View.GONE);
}
Glide.with(context).clear(holder.image);
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java
index 284f3e468..2961796c6 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java
@@ -244,7 +244,7 @@ public class SubscriptionsRecyclerAdapter extends SelectableAdapter<Subscription
count.setVisibility(View.GONE);
}
- CoverLoader coverLoader = new CoverLoader(mainActivityRef.get());
+ CoverLoader coverLoader = new CoverLoader();
boolean textAndImageCombined;
if (drawerItem.type == NavDrawerData.DrawerItem.Type.FEED) {
Feed feed = ((NavDrawerData.FeedDrawerItem) drawerItem).feed;
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java
deleted file mode 100644
index 8acfcb58f..000000000
--- a/app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package de.danoeh.antennapod.asynctask;
-
-import android.content.Context;
-import android.net.Uri;
-import androidx.annotation.NonNull;
-import androidx.documentfile.provider.DocumentFile;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.Charset;
-
-import de.danoeh.antennapod.core.export.ExportWriter;
-import de.danoeh.antennapod.core.storage.DBReader;
-import io.reactivex.Observable;
-
-/**
- * Writes an OPML file into the user selected export directory in the background.
- */
-public class DocumentFileExportWorker {
-
- private final @NonNull ExportWriter exportWriter;
- private @NonNull Context context;
- private @NonNull Uri outputFileUri;
-
- public DocumentFileExportWorker(@NonNull ExportWriter exportWriter, @NonNull Context context, @NonNull Uri outputFileUri) {
- this.exportWriter = exportWriter;
- this.context = context;
- this.outputFileUri = outputFileUri;
- }
-
- public Observable<DocumentFile> exportObservable() {
- DocumentFile output = DocumentFile.fromSingleUri(context, outputFileUri);
- return Observable.create(subscriber -> {
- OutputStream outputStream = null;
- OutputStreamWriter writer = null;
- try {
- Uri uri = output.getUri();
- outputStream = context.getContentResolver().openOutputStream(uri, "wt");
- if (outputStream == null) {
- throw new IOException();
- }
- writer = new OutputStreamWriter(outputStream, Charset.forName("UTF-8"));
- exportWriter.writeDocument(DBReader.getFeedList(), writer, context);
- subscriber.onNext(output);
- } catch (IOException e) {
- subscriber.onError(e);
- } finally {
- if (writer != null) {
- try {
- writer.close();
- } catch (IOException e) {
- subscriber.onError(e);
- }
- }
- if (outputStream != null) {
- try {
- outputStream.close();
- } catch (IOException e) {
- subscriber.onError(e);
- }
- }
- subscriber.onComplete();
- }
- });
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java
deleted file mode 100644
index 97a5f157b..000000000
--- a/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package de.danoeh.antennapod.asynctask;
-
-import android.content.Context;
-import androidx.annotation.NonNull;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.nio.charset.Charset;
-
-import de.danoeh.antennapod.core.export.ExportWriter;
-import de.danoeh.antennapod.storage.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.DBReader;
-import io.reactivex.Observable;
-
-/**
- * Writes an OPML file into the export directory in the background.
- */
-public class ExportWorker {
-
- private static final String EXPORT_DIR = "export/";
- private static final String TAG = "ExportWorker";
- private static final String DEFAULT_OUTPUT_NAME = "antennapod-feeds";
-
- private final @NonNull ExportWriter exportWriter;
- private final @NonNull File output;
- private final Context context;
-
- public ExportWorker(@NonNull ExportWriter exportWriter, Context context) {
- this(exportWriter, new File(UserPreferences.getDataFolder(EXPORT_DIR),
- DEFAULT_OUTPUT_NAME + "." + exportWriter.fileExtension()), context);
- }
-
- private ExportWorker(@NonNull ExportWriter exportWriter, @NonNull File output, Context context) {
- this.exportWriter = exportWriter;
- this.output = output;
- this.context = context;
- }
-
- public Observable<File> exportObservable() {
- if (output.exists()) {
- boolean success = output.delete();
- Log.w(TAG, "Overwriting previously exported file: " + success);
- }
- return Observable.create(subscriber -> {
- OutputStreamWriter writer = null;
- try {
- writer = new OutputStreamWriter(new FileOutputStream(output), Charset.forName("UTF-8"));
- exportWriter.writeDocument(DBReader.getFeedList(), writer, context);
- subscriber.onNext(output);
- } catch (IOException e) {
- subscriber.onError(e);
- } finally {
- if (writer != null) {
- try {
- writer.close();
- } catch (IOException e) {
- subscriber.onError(e);
- }
- }
- subscriber.onComplete();
- }
- });
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
index 4d9c526c0..64b85a94e 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
@@ -256,9 +256,8 @@ public class ProxyDialog {
TypedArray res = context.getTheme().obtainStyledAttributes(new int[] { android.R.attr.textColorPrimary });
int textColorPrimary = res.getColor(0, 0);
res.recycle();
- String checking = context.getString(R.string.proxy_checking);
txtvMessage.setTextColor(textColorPrimary);
- txtvMessage.setText("{fa-circle-o-notch spin} " + checking);
+ txtvMessage.setText(R.string.proxy_checking);
txtvMessage.setVisibility(View.VISIBLE);
disposable = Completable.create(emitter -> {
String type = (String) spType.getSelectedItem();
@@ -300,15 +299,13 @@ public class ProxyDialog {
.subscribe(
() -> {
txtvMessage.setTextColor(ThemeUtils.getColorFromAttr(context, R.attr.icon_green));
- String message = String.format("%s %s", "{fa-check}",
- context.getString(R.string.proxy_test_successful));
- txtvMessage.setText(message);
+ txtvMessage.setText(R.string.proxy_test_successful);
setTestRequired(false);
},
error -> {
error.printStackTrace();
txtvMessage.setTextColor(ThemeUtils.getColorFromAttr(context, R.attr.icon_red));
- String message = String.format("%s %s: %s", "{fa-close}",
+ String message = String.format("%s: %s",
context.getString(R.string.proxy_test_failed), error.getMessage());
txtvMessage.setText(message);
setTestRequired(true);
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/SwipeActionsDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/SwipeActionsDialog.java
index 257158f15..2cd03e21d 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/SwipeActionsDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/SwipeActionsDialog.java
@@ -13,8 +13,7 @@ import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.gridlayout.widget.GridLayout;
-import com.annimon.stream.Stream;
-
+import java.util.ArrayList;
import java.util.List;
import de.danoeh.antennapod.R;
@@ -29,8 +28,16 @@ import de.danoeh.antennapod.fragment.FeedItemlistFragment;
import de.danoeh.antennapod.fragment.InboxFragment;
import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
import de.danoeh.antennapod.fragment.QueueFragment;
+import de.danoeh.antennapod.fragment.swipeactions.AddToQueueSwipeAction;
+import de.danoeh.antennapod.fragment.swipeactions.DeleteSwipeAction;
+import de.danoeh.antennapod.fragment.swipeactions.MarkFavoriteSwipeAction;
+import de.danoeh.antennapod.fragment.swipeactions.RemoveFromHistorySwipeAction;
+import de.danoeh.antennapod.fragment.swipeactions.RemoveFromInboxSwipeAction;
+import de.danoeh.antennapod.fragment.swipeactions.RemoveFromQueueSwipeAction;
+import de.danoeh.antennapod.fragment.swipeactions.StartDownloadSwipeAction;
import de.danoeh.antennapod.fragment.swipeactions.SwipeAction;
import de.danoeh.antennapod.fragment.swipeactions.SwipeActions;
+import de.danoeh.antennapod.fragment.swipeactions.TogglePlaybackStateSwipeAction;
import de.danoeh.antennapod.ui.common.ThemeUtils;
public class SwipeActionsDialog {
@@ -56,47 +63,54 @@ public class SwipeActionsDialog {
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context);
- keys = SwipeActions.swipeActions;
+ keys = new ArrayList<>();
+ if (tag.equals(QueueFragment.TAG)) {
+ keys.add(new RemoveFromQueueSwipeAction());
+ } else {
+ keys.add(new AddToQueueSwipeAction());
+ }
+ if (!tag.equals(CompletedDownloadsFragment.TAG)) {
+ keys.add(new StartDownloadSwipeAction());
+ }
+ if (!tag.equals(CompletedDownloadsFragment.TAG)
+ && ! tag.equals(QueueFragment.TAG)
+ && !tag.equals(PlaybackHistoryFragment.TAG)) {
+ keys.add(new RemoveFromInboxSwipeAction());
+ }
+ if (!tag.equals(InboxFragment.TAG)) {
+ keys.add(new DeleteSwipeAction());
+ }
+ keys.add(new MarkFavoriteSwipeAction());
+ if (tag.equals(PlaybackHistoryFragment.TAG)) {
+ keys.add(new RemoveFromHistorySwipeAction());
+ }
+ if (!tag.equals(InboxFragment.TAG)) {
+ keys.add(new TogglePlaybackStateSwipeAction());
+ }
String forFragment = "";
switch (tag) {
case InboxFragment.TAG:
forFragment = context.getString(R.string.inbox_label);
- keys = Stream.of(keys).filter(a -> !a.getId().equals(SwipeAction.TOGGLE_PLAYED)
- && !a.getId().equals(SwipeAction.DELETE)
- && !a.getId().equals(SwipeAction.REMOVE_FROM_HISTORY)).toList();
break;
case AllEpisodesFragment.TAG:
forFragment = context.getString(R.string.episodes_label);
- keys = Stream.of(keys).filter(a -> !a.getId().equals(SwipeAction.REMOVE_FROM_HISTORY)).toList();
break;
case CompletedDownloadsFragment.TAG:
forFragment = context.getString(R.string.downloads_label);
- keys = Stream.of(keys).filter(a -> !a.getId().equals(SwipeAction.REMOVE_FROM_INBOX)
- && !a.getId().equals(SwipeAction.REMOVE_FROM_HISTORY)
- && !a.getId().equals(SwipeAction.START_DOWNLOAD)).toList();
break;
case FeedItemlistFragment.TAG:
forFragment = context.getString(R.string.individual_subscription);
- keys = Stream.of(keys).filter(a -> !a.getId().equals(SwipeAction.REMOVE_FROM_HISTORY)).toList();
break;
case QueueFragment.TAG:
forFragment = context.getString(R.string.queue_label);
- keys = Stream.of(keys).filter(a -> !a.getId().equals(SwipeAction.ADD_TO_QUEUE)
- && !a.getId().equals(SwipeAction.REMOVE_FROM_INBOX)
- && !a.getId().equals(SwipeAction.REMOVE_FROM_HISTORY)).toList();
break;
case PlaybackHistoryFragment.TAG:
forFragment = context.getString(R.string.playback_history_label);
- keys = Stream.of(keys).filter(a -> !a.getId().equals(SwipeAction.REMOVE_FROM_INBOX)).toList();
break;
default: break;
}
- if (!tag.equals(QueueFragment.TAG)) {
- keys = Stream.of(keys).filter(a -> !a.getId().equals(SwipeAction.REMOVE_FROM_QUEUE)).toList();
- }
-
builder.setTitle(context.getString(R.string.swipeactions_label) + " - " + forFragment);
SwipeactionsDialogBinding viewBinding = SwipeactionsDialogBinding.inflate(LayoutInflater.from(context));
builder.setView(viewBinding.getRoot());
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/TimeRangeDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/TimeRangeDialog.java
index 85913043e..1d84c7c22 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/TimeRangeDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/TimeRangeDialog.java
@@ -139,8 +139,8 @@ public class TimeRangeDialog extends MaterialAlertDialogBuilder {
}
protected Point radToPoint(float angle, float radius) {
- return new Point((int) (getWidth() / 2 + radius * Math.sin(-angle * Math.PI / 180 + Math.PI)),
- (int) (getHeight() / 2 + radius * Math.cos(-angle * Math.PI / 180 + Math.PI)));
+ return new Point((int) (getWidth() / 2.0 + radius * Math.sin(-angle * Math.PI / 180.0 + Math.PI)),
+ (int) (getHeight() / 2.0 + radius * Math.cos(-angle * Math.PI / 180.0 + Math.PI)));
}
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
index 8de7dce04..c62f5df7e 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
@@ -37,6 +37,7 @@ public class VariableSpeedDialog extends BottomSheetDialogFragment {
private final List<Float> selectedSpeeds;
private PlaybackSpeedSeekBar speedSeekBar;
private Chip addCurrentSpeedChip;
+ private CheckBox skipSilenceCheckbox;
public VariableSpeedDialog() {
DecimalFormatSymbols format = new DecimalFormatSymbols(Locale.US);
@@ -51,11 +52,13 @@ public class VariableSpeedDialog extends BottomSheetDialogFragment {
@Override
public void loadMediaInfo() {
updateSpeed(new SpeedChangedEvent(controller.getCurrentPlaybackSpeedMultiplier()));
+ updateSkipSilence(controller.getCurrentPlaybackSkipSilence());
}
};
controller.init();
EventBus.getDefault().register(this);
updateSpeed(new SpeedChangedEvent(controller.getCurrentPlaybackSpeedMultiplier()));
+ updateSkipSilence(controller.getCurrentPlaybackSkipSilence());
}
@Override
@@ -72,6 +75,10 @@ public class VariableSpeedDialog extends BottomSheetDialogFragment {
addCurrentSpeedChip.setText(String.format(Locale.getDefault(), "%1$.2f", event.getNewSpeed()));
}
+ public void updateSkipSilence(boolean skipSilence) {
+ skipSilenceCheckbox.setChecked(skipSilence);
+ }
+
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@@ -97,9 +104,9 @@ public class VariableSpeedDialog extends BottomSheetDialogFragment {
addCurrentSpeedChip.setCloseIconContentDescription(getString(R.string.add_preset));
addCurrentSpeedChip.setOnClickListener(v -> addCurrentSpeed());
- final CheckBox skipSilence = root.findViewById(R.id.skipSilence);
- skipSilence.setChecked(UserPreferences.isSkipSilence());
- skipSilence.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ skipSilenceCheckbox = root.findViewById(R.id.skipSilence);
+ skipSilenceCheckbox.setChecked(UserPreferences.isSkipSilence());
+ skipSilenceCheckbox.setOnCheckedChangeListener((buttonView, isChecked) -> {
UserPreferences.setSkipSilence(isChecked);
controller.setSkipSilence(isChecked);
});
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
index 20cdd2718..16bfaa00a 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
@@ -164,12 +164,6 @@ public class AddFeedFragment extends Fragment {
viewBinding.combinedFeedSearchEditText.post(() -> viewBinding.combinedFeedSearchEditText.setText(""));
}
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setRetainInstance(true);
- }
-
private void chooseOpmlImportPathResult(final Uri uri) {
if (uri == null) {
return;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java
index 8b25c0e6a..bf101445a 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java
@@ -315,12 +315,6 @@ public class AudioPlayerFragment extends Fragment implements
}
@Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setRetainInstance(true);
- }
-
- @Override
public void onStart() {
super.onStart();
controller = newPlaybackController();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java
index 16ccb2af4..7a4927090 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java
@@ -210,9 +210,6 @@ public class DiscoveryFragment extends Fragment implements Toolbar.OnMenuItemCli
@Override
public boolean onMenuItemClick(MenuItem item) {
- if (super.onOptionsItemSelected(item)) {
- return true;
- }
final int itemId = item.getItemId();
if (itemId == R.id.discover_hide_item) {
item.setChecked(!item.isChecked());
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
index 03913ff12..34712d428 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
@@ -3,7 +3,6 @@ package de.danoeh.antennapod.fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
-import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -87,9 +86,9 @@ public class DownloadLogFragment extends BottomSheetDialogFragment
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- Object item = adapter.getItem(position);
- if (item instanceof DownloadResult) {
- new DownloadLogDetailsDialog(getContext(), (DownloadResult) item).show();
+ final DownloadResult item = adapter.getItem(position);
+ if (item != null) {
+ new DownloadLogDetailsDialog(getContext(), item).show();
}
}
@@ -99,15 +98,8 @@ public class DownloadLogFragment extends BottomSheetDialogFragment
}
@Override
- public void onPrepareOptionsMenu(@NonNull Menu menu) {
- menu.findItem(R.id.clear_logs_item).setVisible(!downloadLog.isEmpty());
- }
-
- @Override
public boolean onMenuItemClick(MenuItem item) {
- if (super.onOptionsItemSelected(item)) {
- return true;
- } else if (item.getItemId() == R.id.clear_logs_item) {
+ if (item.getItemId() == R.id.clear_logs_item) {
DBWriter.clearDownloadLog();
return true;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
index 0cbc23a56..08714e971 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
@@ -119,10 +119,7 @@ public abstract class EpisodesListFragment extends Fragment
}
@Override
- public boolean onOptionsItemSelected(@NonNull MenuItem item) {
- if (super.onOptionsItemSelected(item)) {
- return true;
- }
+ public boolean onMenuItemClick(MenuItem item) {
final int itemId = item.getItemId();
if (itemId == R.id.refresh_item) {
FeedUpdateManager.runOnceOrAsk(requireContext());
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
index 8020235b9..b48e99240 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
@@ -24,7 +24,6 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.snackbar.Snackbar;
-import com.joanzapata.iconify.Iconify;
import com.leinardi.android.speeddial.SpeedDialView;
import org.apache.commons.lang3.StringUtils;
@@ -445,9 +444,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
viewBinding.header.txtvFailure.setVisibility(View.GONE);
}
if (!feed.getPreferences().getKeepUpdated()) {
- viewBinding.header.txtvUpdatesDisabled.setText("{md-pause-circle-outline} "
- + this.getString(R.string.updates_disabled_label));
- Iconify.addIcons(viewBinding.header.txtvUpdatesDisabled);
+ viewBinding.header.txtvUpdatesDisabled.setText(R.string.updates_disabled_label);
viewBinding.header.txtvUpdatesDisabled.setVisibility(View.VISIBLE);
} else {
viewBinding.header.txtvUpdatesDisabled.setVisibility(View.GONE);
@@ -457,9 +454,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
if (feed.getItemFilter() != null) {
FeedItemFilter filter = feed.getItemFilter();
if (filter.getValues().length > 0) {
- viewBinding.header.txtvInformation.setText("{md-info-outline} "
- + this.getString(R.string.filtered_label));
- Iconify.addIcons(viewBinding.header.txtvInformation);
+ viewBinding.header.txtvInformation.setText(R.string.filtered_label);
viewBinding.header.txtvInformation.setOnClickListener(l ->
FeedItemFilterDialog.newInstance(feed).show(getChildFragmentManager(), null));
viewBinding.header.txtvInformation.setVisibility(View.VISIBLE);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
index 7e9c3d093..4626c061f 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
@@ -241,14 +241,21 @@ public class FeedSettingsFragment extends Fragment {
PlaybackSpeedFeedSettingDialogBinding.inflate(getLayoutInflater());
viewBinding.seekBar.setProgressChangedListener(speed ->
viewBinding.currentSpeedLabel.setText(String.format(Locale.getDefault(), "%.2fx", speed)));
- float speed = feedPreferences.getFeedPlaybackSpeed();
viewBinding.useGlobalCheckbox.setOnCheckedChangeListener((buttonView, isChecked) -> {
viewBinding.seekBar.setEnabled(!isChecked);
viewBinding.seekBar.setAlpha(isChecked ? 0.4f : 1f);
viewBinding.currentSpeedLabel.setAlpha(isChecked ? 0.4f : 1f);
+
+ viewBinding.skipSilenceFeed.setEnabled(!isChecked);
+ viewBinding.skipSilenceFeed.setAlpha(isChecked ? 0.4f : 1f);
});
- viewBinding.useGlobalCheckbox.setChecked(speed == FeedPreferences.SPEED_USE_GLOBAL);
- viewBinding.seekBar.updateSpeed(speed == FeedPreferences.SPEED_USE_GLOBAL ? 1 : speed);
+ float speed = feedPreferences.getFeedPlaybackSpeed();
+ FeedPreferences.SkipSilence skipSilence = feedPreferences.getFeedSkipSilence();
+ boolean isGlobal = speed == FeedPreferences.SPEED_USE_GLOBAL;
+ viewBinding.useGlobalCheckbox.setChecked(isGlobal);
+ viewBinding.seekBar.updateSpeed(isGlobal ? 1 : speed);
+ viewBinding.skipSilenceFeed.setChecked(!isGlobal
+ && skipSilence == FeedPreferences.SkipSilence.AGGRESSIVE);
new MaterialAlertDialogBuilder(getContext())
.setTitle(R.string.playback_speed)
.setView(viewBinding.getRoot())
@@ -256,9 +263,19 @@ public class FeedSettingsFragment extends Fragment {
float newSpeed = viewBinding.useGlobalCheckbox.isChecked()
? FeedPreferences.SPEED_USE_GLOBAL : viewBinding.seekBar.getCurrentSpeed();
feedPreferences.setFeedPlaybackSpeed(newSpeed);
+ FeedPreferences.SkipSilence newSkipSilence;
+ if (viewBinding.useGlobalCheckbox.isChecked()) {
+ newSkipSilence = FeedPreferences.SkipSilence.GLOBAL;
+ } else if (viewBinding.skipSilenceFeed.isChecked()) {
+ newSkipSilence = FeedPreferences.SkipSilence.AGGRESSIVE;
+ } else {
+ newSkipSilence = FeedPreferences.SkipSilence.OFF;
+ }
+ feedPreferences.setFeedSkipSilence(newSkipSilence);
DBWriter.setFeedPreferences(feedPreferences);
- EventBus.getDefault().post(
- new SpeedPresetChangedEvent(feedPreferences.getFeedPlaybackSpeed(), feed.getId()));
+ EventBus.getDefault().post(new SpeedPresetChangedEvent(
+ feedPreferences.getFeedPlaybackSpeed(),
+ feed.getId(), feedPreferences.getFeedSkipSilence()));
})
.setNegativeButton(R.string.cancel_label, null)
.show();
@@ -421,6 +438,9 @@ public class FeedSettingsFragment extends Fragment {
case ADD_TO_INBOX:
newEpisodesAction.setSummary(R.string.feed_new_episodes_action_add_to_inbox);
break;
+ case ADD_TO_QUEUE:
+ newEpisodesAction.setSummary(R.string.feed_new_episodes_action_add_to_queue);
+ break;
case NOTHING:
newEpisodesAction.setSummary(R.string.feed_new_episodes_action_nothing);
break;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java
index 636c0245b..4c3647669 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java
@@ -359,10 +359,10 @@ public class NavDrawerFragment extends Fragment implements SharedPreferences.OnS
.setState(BottomSheetBehavior.STATE_COLLAPSED);
} else {
NavDrawerData.TagDrawerItem folder = ((NavDrawerData.TagDrawerItem) clickedItem);
- if (openFolders.contains(folder.name)) {
- openFolders.remove(folder.name);
+ if (openFolders.contains(folder.getTitle())) {
+ openFolders.remove(folder.getTitle());
} else {
- openFolders.add(folder.name);
+ openFolders.add(folder.getTitle());
}
getContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
@@ -438,8 +438,8 @@ public class NavDrawerFragment extends Fragment implements SharedPreferences.OnS
flatItems.add(item);
if (item.type == NavDrawerData.DrawerItem.Type.TAG) {
NavDrawerData.TagDrawerItem folder = ((NavDrawerData.TagDrawerItem) item);
- folder.isOpen = openFolders.contains(folder.name);
- if (folder.isOpen) {
+ folder.setOpen(openFolders.contains(folder.getTitle()));
+ if (folder.isOpen()) {
flatItems.addAll(makeFlatDrawerData(((NavDrawerData.TagDrawerItem) item).children, layer + 1));
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
index 003ee23db..5e9146fe9 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -101,7 +101,6 @@ public class QueueFragment extends Fragment implements MaterialToolbar.OnMenuIte
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setRetainInstance(true);
prefs = getActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
index 0f959d9d1..8c976ae7c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
@@ -122,7 +122,6 @@ public class SearchFragment extends Fragment implements EpisodeItemListAdapter.O
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setRetainInstance(true);
automaticSearchDebouncer = new Handler(Looper.getMainLooper());
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
index e86cd58b9..811d46f2c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
@@ -102,8 +102,6 @@ public class SubscriptionFragment extends Fragment
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setRetainInstance(true);
-
prefs = requireActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/DownloadsPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/DownloadsPreferencesFragment.java
index c17066fef..91ffa1c4f 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/DownloadsPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/DownloadsPreferencesFragment.java
@@ -96,13 +96,13 @@ public class DownloadsPreferencesFragment extends PreferenceFragmentCompat
private void showAutoDeleteEnableDialog() {
new MaterialAlertDialogBuilder(requireContext())
- .setMessage(R.string.pref_auto_local_delete_dialog_body)
- .setPositiveButton(R.string.yes, (dialog, which) -> {
- blockAutoDeleteLocal = false;
- ((TwoStatePreference) findPreference(PREF_AUTO_DELETE_LOCAL)).setChecked(true);
- blockAutoDeleteLocal = true;
- })
- .setNegativeButton(R.string.cancel_label, null)
- .show();
+ .setMessage(R.string.pref_auto_local_delete_dialog_body)
+ .setPositiveButton(R.string.yes, (dialog, which) -> {
+ blockAutoDeleteLocal = false;
+ ((TwoStatePreference) findPreference(PREF_AUTO_DELETE_LOCAL)).setChecked(true);
+ blockAutoDeleteLocal = true;
+ })
+ .setNegativeButton(R.string.cancel_label, null)
+ .show();
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
index 686be884c..9191825aa 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
@@ -16,6 +16,7 @@ import androidx.activity.result.contract.ActivityResultContracts.GetContent;
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
+import androidx.documentfile.provider.DocumentFile;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import androidx.core.app.ShareCompat;
import androidx.core.content.FileProvider;
@@ -25,13 +26,15 @@ import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.OpmlImportActivity;
import de.danoeh.antennapod.activity.PreferenceActivity;
-import de.danoeh.antennapod.asynctask.DocumentFileExportWorker;
-import de.danoeh.antennapod.asynctask.ExportWorker;
-import de.danoeh.antennapod.core.export.ExportWriter;
-import de.danoeh.antennapod.core.export.favorites.FavoritesWriter;
-import de.danoeh.antennapod.core.export.html.HtmlWriter;
-import de.danoeh.antennapod.core.export.opml.OpmlWriter;
-import de.danoeh.antennapod.core.storage.DatabaseExporter;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.model.feed.FeedItem;
+import de.danoeh.antennapod.model.feed.FeedItemFilter;
+import de.danoeh.antennapod.model.feed.SortOrder;
+import de.danoeh.antennapod.storage.importexport.DatabaseExporter;
+import de.danoeh.antennapod.storage.importexport.FavoritesWriter;
+import de.danoeh.antennapod.storage.importexport.HtmlWriter;
+import de.danoeh.antennapod.storage.importexport.OpmlWriter;
+import de.danoeh.antennapod.storage.preferences.UserPreferences;
import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
@@ -39,8 +42,14 @@ import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
+import java.util.List;
import java.util.Locale;
public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
@@ -57,18 +66,29 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
private static final String CONTENT_TYPE_HTML = "text/html";
private static final String DEFAULT_FAVORITES_OUTPUT_NAME = "antennapod-favorites-%s.html";
private static final String DATABASE_EXPORT_FILENAME = "AntennaPodBackup-%s.db";
+
private final ActivityResultLauncher<Intent> chooseOpmlExportPathLauncher =
- registerForActivityResult(new StartActivityForResult(), this::chooseOpmlExportPathResult);
+ registerForActivityResult(new StartActivityForResult(),
+ result -> exportToDocument(result, Export.OPML));
private final ActivityResultLauncher<Intent> chooseHtmlExportPathLauncher =
- registerForActivityResult(new StartActivityForResult(), this::chooseHtmlExportPathResult);
+ registerForActivityResult(new StartActivityForResult(),
+ result -> exportToDocument(result, Export.HTML));
private final ActivityResultLauncher<Intent> chooseFavoritesExportPathLauncher =
- registerForActivityResult(new StartActivityForResult(), this::chooseFavoritesExportPathResult);
+ registerForActivityResult(new StartActivityForResult(),
+ result -> exportToDocument(result, Export.FAVORITES));
private final ActivityResultLauncher<Intent> restoreDatabaseLauncher =
registerForActivityResult(new StartActivityForResult(), this::restoreDatabaseResult);
private final ActivityResultLauncher<String> backupDatabaseLauncher =
registerForActivityResult(new BackupDatabase(), this::backupDatabaseResult);
private final ActivityResultLauncher<String> chooseOpmlImportPathLauncher =
- registerForActivityResult(new GetContent(), this::chooseOpmlImportPathResult);
+ registerForActivityResult(new GetContent(), uri -> {
+ if (uri != null) {
+ final Intent intent = new Intent(getContext(), OpmlImportActivity.class);
+ intent.setData(uri);
+ startActivity(intent);
+ }
+ });
+
private Disposable disposable;
private ProgressDialog progressDialog;
@@ -95,20 +115,16 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
}
}
- private String dateStampFilename(String fname) {
- return String.format(fname, new SimpleDateFormat("yyyy-MM-dd", Locale.US).format(new Date()));
- }
-
private void setupStorageScreen() {
findPreference(PREF_OPML_EXPORT).setOnPreferenceClickListener(
preference -> {
- openExportPathPicker(Export.OPML, chooseOpmlExportPathLauncher, new OpmlWriter());
+ openExportPathPicker(Export.OPML, chooseOpmlExportPathLauncher);
return true;
}
);
findPreference(PREF_HTML_EXPORT).setOnPreferenceClickListener(
preference -> {
- openExportPathPicker(Export.HTML, chooseHtmlExportPathLauncher, new HtmlWriter());
+ openExportPathPicker(Export.HTML, chooseHtmlExportPathLauncher);
return true;
});
findPreference(PREF_OPML_IMPORT).setOnPreferenceClickListener(
@@ -132,32 +148,13 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
});
findPreference(PREF_FAVORITE_EXPORT).setOnPreferenceClickListener(
preference -> {
- openExportPathPicker(Export.FAVORITES, chooseFavoritesExportPathLauncher, new FavoritesWriter());
+ openExportPathPicker(Export.FAVORITES, chooseFavoritesExportPathLauncher);
return true;
});
}
- private void exportWithWriter(ExportWriter exportWriter, Uri uri, Export exportType) {
- Context context = getActivity();
- progressDialog.show();
- if (uri == null) {
- Observable<File> observable = new ExportWorker(exportWriter, getContext()).exportObservable();
- disposable = observable.subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(output -> {
- Uri fileUri = FileProvider.getUriForFile(context.getApplicationContext(),
- context.getString(R.string.provider_authority), output);
- showExportSuccessSnackbar(fileUri, exportType.contentType);
- }, this::showExportErrorDialog, progressDialog::dismiss);
- } else {
- DocumentFileExportWorker worker = new DocumentFileExportWorker(exportWriter, context, uri);
- disposable = worker.exportObservable()
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(output ->
- showExportSuccessSnackbar(output.getUri(), exportType.contentType),
- this::showExportErrorDialog, progressDialog::dismiss);
- }
+ private String dateStampFilename(String fname) {
+ return String.format(fname, new SimpleDateFormat("yyyy-MM-dd", Locale.US).format(new Date()));
}
private void exportDatabase() {
@@ -211,30 +208,6 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
alert.show();
}
- private void chooseOpmlExportPathResult(final ActivityResult result) {
- if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) {
- return;
- }
- final Uri uri = result.getData().getData();
- exportWithWriter(new OpmlWriter(), uri, Export.OPML);
- }
-
- private void chooseHtmlExportPathResult(final ActivityResult result) {
- if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) {
- return;
- }
- final Uri uri = result.getData().getData();
- exportWithWriter(new HtmlWriter(), uri, Export.HTML);
- }
-
- private void chooseFavoritesExportPathResult(final ActivityResult result) {
- if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) {
- return;
- }
- final Uri uri = result.getData().getData();
- exportWithWriter(new FavoritesWriter(), uri, Export.FAVORITES);
- }
-
private void restoreDatabaseResult(final ActivityResult result) {
if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) {
return;
@@ -264,16 +237,7 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
}, this::showExportErrorDialog);
}
- private void chooseOpmlImportPathResult(final Uri uri) {
- if (uri == null) {
- return;
- }
- final Intent intent = new Intent(getContext(), OpmlImportActivity.class);
- intent.setData(uri);
- startActivity(intent);
- }
-
- private void openExportPathPicker(Export exportType, ActivityResultLauncher<Intent> result, ExportWriter writer) {
+ private void openExportPathPicker(Export exportType, ActivityResultLauncher<Intent> result) {
String title = dateStampFilename(exportType.outputNameTemplate);
Intent intentPickAction = new Intent(Intent.ACTION_CREATE_DOCUMENT)
@@ -292,10 +256,86 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
// If we are using a SDK lower than API 21 or the implicit intent failed
// fallback to the legacy export process
- exportWithWriter(writer, null, exportType);
+ File output = new File(UserPreferences.getDataFolder("export/"), title);
+ exportToFile(exportType, output);
+ }
+
+ private void exportToFile(Export exportType, File output) {
+ progressDialog.show();
+ disposable = Observable.create(
+ subscriber -> {
+ if (output.exists()) {
+ boolean success = output.delete();
+ Log.w(TAG, "Overwriting previously exported file: " + success);
+ }
+ try (FileOutputStream fileOutputStream = new FileOutputStream(output)) {
+ writeToStream(fileOutputStream, exportType);
+ subscriber.onNext(output);
+ } catch (IOException e) {
+ subscriber.onError(e);
+ }
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(outputFile -> {
+ progressDialog.dismiss();
+ Uri fileUri = FileProvider.getUriForFile(getActivity().getApplicationContext(),
+ getString(R.string.provider_authority), output);
+ showExportSuccessSnackbar(fileUri, exportType.contentType);
+ }, this::showExportErrorDialog, progressDialog::dismiss);
+ }
+
+ private void exportToDocument(final ActivityResult result, Export exportType) {
+ if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) {
+ return;
+ }
+ progressDialog.show();
+ DocumentFile output = DocumentFile.fromSingleUri(getContext(), result.getData().getData());
+ disposable = Observable.create(
+ subscriber -> {
+ try (OutputStream outputStream = getContext().getContentResolver()
+ .openOutputStream(output.getUri(), "wt")) {
+ writeToStream(outputStream, exportType);
+ subscriber.onNext(output);
+ } catch (IOException e) {
+ subscriber.onError(e);
+ }
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(ignore -> {
+ progressDialog.dismiss();
+ showExportSuccessSnackbar(output.getUri(), exportType.contentType);
+ }, this::showExportErrorDialog, progressDialog::dismiss);
+ }
+
+ private void writeToStream(OutputStream outputStream, Export type) throws IOException {
+ try (OutputStreamWriter writer = new OutputStreamWriter(outputStream, Charset.forName("UTF-8"))) {
+ switch (type) {
+ case HTML:
+ HtmlWriter.writeDocument(DBReader.getFeedList(), writer, getContext());
+ break;
+ case OPML:
+ OpmlWriter.writeDocument(DBReader.getFeedList(), writer);
+ break;
+ case FAVORITES:
+ List<FeedItem> allFavorites = DBReader.getEpisodes(0, Integer.MAX_VALUE,
+ new FeedItemFilter(FeedItemFilter.IS_FAVORITE), SortOrder.DATE_NEW_OLD);
+ FavoritesWriter.writeDocument(allFavorites, writer, getContext());
+ break;
+ default:
+ showExportErrorDialog(new Exception("Invalid export type"));
+ break;
+ }
+ }
}
private static class BackupDatabase extends ActivityResultContracts.CreateDocument {
+
+ BackupDatabase() {
+ super("application/x-sqlite3");
+ }
+
@NonNull
@Override
public Intent createIntent(@NonNull final Context context, @NonNull final String input) {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java
index 0f3320e98..af48c705d 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java
@@ -6,12 +6,19 @@ import android.os.Build;
import android.os.Bundle;
import android.widget.Button;
import android.widget.ListView;
+
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
+
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.snackbar.Snackbar;
+
+import org.greenrobot.eventbus.EventBus;
+
+import java.util.List;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.dialog.DrawerPreferencesDialog;
@@ -20,9 +27,6 @@ import de.danoeh.antennapod.dialog.SubscriptionsFilterDialog;
import de.danoeh.antennapod.event.PlayerStatusEvent;
import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.storage.preferences.UserPreferences;
-import org.greenrobot.eventbus.EventBus;
-
-import java.util.List;
public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat {
private static final String PREF_SWIPE = "prefSwipe";
@@ -93,38 +97,31 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat {
}
}
-
private void showFullNotificationButtonsDialog() {
final Context context = getActivity();
final List<Integer> preferredButtons = UserPreferences.getFullNotificationButtons();
final String[] allButtonNames = context.getResources().getStringArray(
R.array.full_notification_buttons_options);
- final int[] buttonIDs = {2, 3, 4};
- final int exactItems = 2;
+ final int[] buttonIds = {
+ UserPreferences.NOTIFICATION_BUTTON_SKIP,
+ UserPreferences.NOTIFICATION_BUTTON_NEXT_CHAPTER,
+ UserPreferences.NOTIFICATION_BUTTON_PLAYBACK_SPEED,
+ UserPreferences.NOTIFICATION_BUTTON_SLEEP_TIMER,
+ };
final DialogInterface.OnClickListener completeListener = (dialog, which) ->
UserPreferences.setFullNotificationButtons(preferredButtons);
- final String title = context.getResources().getString(
- R.string.pref_full_notification_buttons_title);
+ final String title = context.getResources().getString(R.string.pref_full_notification_buttons_title);
- showNotificationButtonsDialog(preferredButtons, allButtonNames, buttonIDs, title,
- exactItems, completeListener
- );
- }
-
- private void showNotificationButtonsDialog(List<Integer> preferredButtons,
- String[] allButtonNames, int[] buttonIds, String title,
- int exactItems, DialogInterface.OnClickListener completeListener) {
boolean[] checked = new boolean[allButtonNames.length]; // booleans default to false in java
- final Context context = getActivity();
-
// Clear buttons that are not part of the setting anymore
for (int i = preferredButtons.size() - 1; i >= 0; i--) {
boolean isValid = false;
for (int j = 0; j < checked.length; j++) {
if (buttonIds[j] == preferredButtons.get(i)) {
isValid = true;
+ break;
}
}
@@ -133,7 +130,7 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat {
}
}
- for(int i=0; i < checked.length; i++) {
+ for (int i = 0; i < checked.length; i++) {
if (preferredButtons.contains(buttonIds[i])) {
checked[i] = true;
}
@@ -143,7 +140,6 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat {
builder.setTitle(title);
builder.setMultiChoiceItems(allButtonNames, checked, (dialog, which, isChecked) -> {
checked[which] = isChecked;
-
if (isChecked) {
preferredButtons.add(buttonIds[which]);
} else {
@@ -159,19 +155,17 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat {
Button positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
positiveButton.setOnClickListener(v -> {
- if (preferredButtons.size() != exactItems) {
+ if (preferredButtons.size() != 2) {
ListView selectionView = dialog.getListView();
Snackbar.make(
selectionView,
- String.format(context.getResources().getString(
- R.string.pref_compact_notification_buttons_dialog_error_exact), exactItems),
+ context.getResources().getString(R.string.pref_compact_notification_buttons_dialog_error_exact),
Snackbar.LENGTH_SHORT).show();
} else {
completeListener.onClick(dialog, AlertDialog.BUTTON_POSITIVE);
dialog.cancel();
}
- }
- );
+ });
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/about/ContributorsPagerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/about/ContributorsPagerFragment.java
index caa8031ae..139413157 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/about/ContributorsPagerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/about/ContributorsPagerFragment.java
@@ -26,7 +26,6 @@ public class ContributorsPagerFragment extends Fragment {
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
- setHasOptionsMenu(true);
View rootView = inflater.inflate(R.layout.pager_fragment, container, false);
ViewPager2 viewPager = rootView.findViewById(R.id.viewpager);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/dialog/PreferenceSwitchDialog.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/dialog/PreferenceSwitchDialog.java
index 69319c11e..10fbe6137 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/dialog/PreferenceSwitchDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/dialog/PreferenceSwitchDialog.java
@@ -5,7 +5,7 @@ import android.view.LayoutInflater;
import android.view.View;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-import androidx.appcompat.widget.SwitchCompat;
+import com.google.android.material.materialswitch.MaterialSwitch;
import de.danoeh.antennapod.R;
@@ -38,7 +38,7 @@ public class PreferenceSwitchDialog {
LayoutInflater inflater = LayoutInflater.from(this.context);
View layout = inflater.inflate(R.layout.dialog_switch_preference, null, false);
- SwitchCompat switchButton = layout.findViewById(R.id.dialogSwitch);
+ MaterialSwitch switchButton = layout.findViewById(R.id.dialogSwitch);
switchButton.setText(text);
builder.setView(layout);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/swipeactions/SwipeActions.java b/app/src/main/java/de/danoeh/antennapod/fragment/swipeactions/SwipeActions.java
index beafe2604..bc8cd75c4 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/swipeactions/SwipeActions.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/swipeactions/SwipeActions.java
@@ -13,8 +13,6 @@ import androidx.lifecycle.OnLifecycleEvent;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
-import com.annimon.stream.Stream;
-
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -37,12 +35,11 @@ public class SwipeActions extends ItemTouchHelper.SimpleCallback implements Life
public static final String KEY_PREFIX_SWIPEACTIONS = "PrefSwipeActions";
public static final String KEY_PREFIX_NO_ACTION = "PrefNoSwipeAction";
- public static final List<SwipeAction> swipeActions = Collections.unmodifiableList(
+ private static final List<SwipeAction> swipeActions = Collections.unmodifiableList(
Arrays.asList(new AddToQueueSwipeAction(), new RemoveFromInboxSwipeAction(),
new StartDownloadSwipeAction(), new MarkFavoriteSwipeAction(),
new TogglePlaybackStateSwipeAction(), new RemoveFromQueueSwipeAction(),
- new DeleteSwipeAction(), new RemoveFromHistorySwipeAction())
- );
+ new DeleteSwipeAction(), new RemoveFromHistorySwipeAction()));
private final Fragment fragment;
private final String tag;
@@ -65,6 +62,15 @@ public class SwipeActions extends ItemTouchHelper.SimpleCallback implements Life
this(0, fragment, tag);
}
+ public static SwipeAction getAction(String key) {
+ for (SwipeAction action : swipeActions) {
+ if (action.getId().equals(key)) {
+ return action;
+ }
+ }
+ return null;
+ }
+
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void reloadPreference() {
actions = getPrefs(fragment.requireContext(), tag);
@@ -255,10 +261,8 @@ public class SwipeActions extends ItemTouchHelper.SimpleCallback implements Life
public Actions(String prefs) {
String[] actions = prefs.split(",");
if (actions.length == 2) {
- this.right = Stream.of(swipeActions)
- .filter(a -> a.getId().equals(actions[0])).single();
- this.left = Stream.of(swipeActions)
- .filter(a -> a.getId().equals(actions[1])).single();
+ right = getAction(actions[0]);
+ left = getAction(actions[1]);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java
index 6f43a8ff4..3c8d8fc52 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java
@@ -162,7 +162,7 @@ public class HomeFragment extends Fragment implements Toolbar.OnMenuItemClickLis
((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance());
return true;
}
- return super.onOptionsItemSelected(item);
+ return false;
}
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/view/LiftOnScrollListener.java b/app/src/main/java/de/danoeh/antennapod/view/LiftOnScrollListener.java
index 1e53ee828..020fb40e8 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/LiftOnScrollListener.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/LiftOnScrollListener.java
@@ -41,7 +41,7 @@ public class LiftOnScrollListener extends RecyclerView.OnScrollListener
}
@Override
- public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
+ public void onScrollChange(@NonNull NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
elevate(scrollY != 0);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/LocalDeleteModal.java b/app/src/main/java/de/danoeh/antennapod/view/LocalDeleteModal.java
index 4241cadca..a3f541e06 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/LocalDeleteModal.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/LocalDeleteModal.java
@@ -23,10 +23,10 @@ public class LocalDeleteModal {
}
new MaterialAlertDialogBuilder(context)
- .setTitle(R.string.delete_episode_label)
- .setMessage(R.string.delete_local_feed_warning_body)
- .setPositiveButton(R.string.delete_label, (dialog, which) -> deleteCommand.run())
- .setNegativeButton(R.string.cancel_label, null)
- .show();
+ .setTitle(R.string.delete_episode_label)
+ .setMessage(R.string.delete_local_feed_warning_body)
+ .setPositiveButton(R.string.delete_label, (dialog, which) -> deleteCommand.run())
+ .setNegativeButton(R.string.cancel_label, null)
+ .show();
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/viewholder/DownloadLogItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/viewholder/DownloadLogItemViewHolder.java
index 578e1b149..ffb679830 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/viewholder/DownloadLogItemViewHolder.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/viewholder/DownloadLogItemViewHolder.java
@@ -9,7 +9,6 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
-import com.joanzapata.iconify.widget.IconTextView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.ui.common.CircularProgressBar;
@@ -17,7 +16,7 @@ public class DownloadLogItemViewHolder extends RecyclerView.ViewHolder {
public final View secondaryActionButton;
public final ImageView secondaryActionIcon;
public final CircularProgressBar secondaryActionProgress;
- public final IconTextView icon;
+ public final ImageView icon;
public final TextView title;
public final TextView status;
public final TextView reason;
@@ -26,7 +25,7 @@ public class DownloadLogItemViewHolder extends RecyclerView.ViewHolder {
public DownloadLogItemViewHolder(Context context, ViewGroup parent) {
super(LayoutInflater.from(context).inflate(R.layout.downloadlog_item, parent, false));
status = itemView.findViewById(R.id.status);
- icon = itemView.findViewById(R.id.txtvIcon);
+ icon = itemView.findViewById(R.id.icon);
reason = itemView.findViewById(R.id.txtvReason);
tapForDetails = itemView.findViewById(R.id.txtvTapForDetails);
secondaryActionButton = itemView.findViewById(R.id.secondaryActionButton);
diff --git a/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java
index 01d4a10f0..9f0350b17 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java
@@ -15,7 +15,6 @@ import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.elevation.SurfaceColors;
-import com.joanzapata.iconify.Iconify;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
@@ -129,7 +128,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder {
}
if (coverHolder.getVisibility() == View.VISIBLE) {
- new CoverLoader(activity)
+ new CoverLoader()
.withUri(ImageResourceUtils.getEpisodeListImageLocation(item))
.withFallbackUri(item.getFeed().getImageUrl())
.withPlaceholderView(placeholder)
@@ -187,8 +186,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder {
if (media.getSize() > 0) {
size.setText(Formatter.formatShortFileSize(activity, media.getSize()));
} else if (NetworkUtils.isEpisodeHeadDownloadAllowed() && !media.checkedOnSizeButUnknown()) {
- size.setText("{fa-spinner}");
- Iconify.addIcons(size);
+ size.setText("");
MediaSizeLoader.getFeedMediaSizeObservable(media).subscribe(
sizeValue -> {
if (sizeValue > 0) {
@@ -225,7 +223,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder {
itemView.setBackgroundResource(ThemeUtils.getDrawableFromAttr(activity, R.attr.selectableItemBackground));
placeholder.setText("");
if (coverHolder.getVisibility() == View.VISIBLE) {
- new CoverLoader(activity)
+ new CoverLoader()
.withResource(R.color.medium_gray)
.withPlaceholderView(placeholder)
.withCoverView(cover)
diff --git a/app/src/main/java/de/danoeh/antennapod/view/viewholder/HorizontalItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/viewholder/HorizontalItemViewHolder.java
index 21a29a920..8d44f419e 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/viewholder/HorizontalItemViewHolder.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/viewholder/HorizontalItemViewHolder.java
@@ -58,7 +58,7 @@ public class HorizontalItemViewHolder extends RecyclerView.ViewHolder {
card.setAlpha(1.0f);
float density = activity.getResources().getDisplayMetrics().density;
card.setCardBackgroundColor(SurfaceColors.getColorForElevation(activity, 1 * density));
- new CoverLoader(activity)
+ new CoverLoader()
.withUri(ImageResourceUtils.getEpisodeListImageLocation(item))
.withFallbackUri(item.getFeed().getImageUrl())
.withCoverView(cover)
@@ -102,7 +102,7 @@ public class HorizontalItemViewHolder extends RecyclerView.ViewHolder {
public void bindDummy() {
card.setAlpha(0.1f);
- new CoverLoader(activity)
+ new CoverLoader()
.withResource(android.R.color.transparent)
.withCoverView(cover)
.load();
diff --git a/app/src/main/play b/app/src/main/play
new file mode 160000
+Subproject f88328d81d6509487cba71bc4b2bbe96cc47206
diff --git a/app/src/main/play/contact-email.txt b/app/src/main/play/contact-email.txt
deleted file mode 100644
index a35ca7725..000000000
--- a/app/src/main/play/contact-email.txt
+++ /dev/null
@@ -1 +0,0 @@
-info@antennapod.org \ No newline at end of file
diff --git a/app/src/main/play/contact-website.txt b/app/src/main/play/contact-website.txt
deleted file mode 100644
index cb1c2f641..000000000
--- a/app/src/main/play/contact-website.txt
+++ /dev/null
@@ -1 +0,0 @@
-https://github.com/AntennaPod/AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/default-language.txt b/app/src/main/play/default-language.txt
deleted file mode 100644
index f2b0341fe..000000000
--- a/app/src/main/play/default-language.txt
+++ /dev/null
@@ -1 +0,0 @@
-en-US \ No newline at end of file
diff --git a/app/src/main/play/listings/ar/full-description.txt b/app/src/main/play/listings/ar/full-description.txt
deleted file mode 100644
index c84e9892f..000000000
--- a/app/src/main/play/listings/ar/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod هو مدير ومشغل للبودكاست يتيح لك ملايين البودكاستات المجانية والمدفوعة ، من ناشري البودكاستات المستقلين إلى دور النشر الكبيرة مثل BBC و NPR و CNN. قم بإضافة أواستيراد أوتصدير قنواتهم بدون متاعب باستخدام قاعدة بيانات بودكاست iTunes أو ملفات OPML أو عناوين الروابط البسيطة الـ RSS.
-قم بتنزيل الحلقات أو دفقها أو وضعها في لائحة الاستماع واستمتع بها بالطريقة التي تريدها مع سرعات تشغيل قابلة للتعديل ودعم الفصول وضبط وقت النوم.
-وفر الجهد وطاقة البطارية وبيانات المحمول باستخدام أدوات الأتمتة القوية لتنزيل الحلقات (حدد الأوقات والمدد الزمنية وشبكات WiFi) وحذف الحلقات (بناءً على المفضلة وإعدادات التأجيل).
-
-تم صنع AntennaPod من قبل عشاق البودكاست ، وهو مجاني بكل ما تحمله الكلمة من معنى: مفتوح المصدر ، بدون تكاليف ، وبدون إعلانات.
-
-<b>أستورد ونظم وشغل</b>
-• تحكم في التشغيل من أي مكان: بريمج واجهة شاشة الهاتف الرئيسية أوتنبيهات النظام أوسماعة الأذن أوالبلوتوث
-• إضافة واستيراد قنوات عبرأدلة iTunes و gPodder.net وملفات OPML وروابط RSS أو Atom
-• استمتع بالاستماع على هواك مع سرعة تشغيل قابلة للتعديل ، ودعم الفصول ، وموضع تشغيل محفوظ وضبط موعد النوم (اهتز لإعادة الضبط ، ومستوى صوت أقل)
-• الوصول إلى القنوات والحلقات المحمية بكلمة مرور
-
-<b>تابع وشارك وقدر</b>
-تابع أفضل الحلقات بإضافتها للمفضلة
-• أكتشف تلك الحلقة المميزة من خلال سجل التشغيل أو عن طريق البحث في العناوين أو ملاحظات الحلقات
-• مشاركة الحلقات والقنوات من خلال وسائل التواصل الاجتماعي والبريد الإلكتروني وخدمات gPodder.net وعبر تصدير OPML
-
-<b>تحكم في النظام</b>
-• تحكم في التنزيل الآلي: اختر القنوات ، واستبعد التنزيل على شبكات المحمول ، وحدد شبكات WiFi معينة ، وأشترط أن يكون الهاتف متصل بالشاحن أثناء التنزيل وحدد الأوقات أو المدد الزمنية المناسبة للتنزيل.
-• تحكم في سعة التخزين عن طريق تحديد مقدار الحلقات المخزنة والحذف الذكي واختيار موقعك المفضل
-• تكيف مع بيئتك باستخدام النمط الفاتح أوالداكن
-• قم بعمل نسخة احتياطية من اشتراكاتك من خلال الربط مع gPodder.net وتصدير OPML
-
-<b>أنضم إلى مجتمع </b>AntennaPod
-AntennaPod تحت التطوير المستمر من قبل متطوعين. يمكنك المساهمة أيضًا ، بالبرمجة أو بتعليقاتك!
-
-يسعد أعضاء المنتدى بالمساعدة في كل سؤال لديك. أنت مدعو لمناقشة خصائص التطبيق والبودكاستات بشكل عام.
-https://forum.antennapod.org/
-
-Transifex هو المكان المناسب للمساعدة في الترجمة:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/ar/short-description.txt b/app/src/main/play/listings/ar/short-description.txt
deleted file mode 100644
index e04c95acf..000000000
--- a/app/src/main/play/listings/ar/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-مدير ومشغل بودكاست سهل الاستخدام ومرن ومفتوح المصدر \ No newline at end of file
diff --git a/app/src/main/play/listings/ar/title.txt b/app/src/main/play/listings/ar/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/ar/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/bg/full-description.txt b/app/src/main/play/listings/bg/full-description.txt
deleted file mode 100644
index 49e556b25..000000000
--- a/app/src/main/play/listings/bg/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod е мениджър и плейър на подкасти, който ви дава незабавен достъп до милиони безплатни и платени подкасти, от независими подкастери до големи издателства като BBC, NPR и CNN. Добавяйте, импортирайте и експортирайте техните емисии безпроблемно, като използвате подкаст базата данни на iTunes, OPML файлове или прости RSS URL адреси.
-Изтегли епизоди, пусни ги в ефир или ги прибави към списък и им се наслади по начина по който ти харесва с настройваща се скорост на записа, подружка за глави и таймер за заспиване.
-Спести усилие, батерия и мобилни данни с мощни автоматизиран контрол за изтегляне на епизоди (учотни време, интевал или безжична връзка) и за изтриване на епизоди (спрямо твоите настройки за любими и забавяния).
-
-Направен от подкаст ентусиасти, AntennaPod е безплатен във всеки смисъл на думата: отворен, без пари, без реклами.
-
-<b>Вмъкни, организирай и пусни</b>
-Управлявай възпроизвеждането отвсякъде: акранно приложение, системните известия или бутоните на безжичните слушалки
-Прибави и вмъкни списъци чрез базаданните на iTunes и gPodder.net, OPML файлове и RSS или линкове от Atom
-• Enjoy listening your way with adjustable playback speed, chapter support, remembered playback position and an advanced sleep timer (shake to reset, lower volume)
-• Access password-protected feeds and episodes
-
-<b>Keep track, share & appreciate</b>
-• Keep track of the best of the best by marking episodes as favourites
-Намери определен епизод чрез историята на възпройзвежданията или чрез търсене на заглавия и белеки към предаванията.
-• Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export
-
-<b>Управлявай системата</b>
-• Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals
-• Manage storage by setting the amount of cached episodes, smart deletion and selecting your preferred location
-• Приспособи се към околната среда със светла и тъмна тема
-• Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Присъедини се към AntennaPod обществото!</b>
-AntennaPod се разработва активно от доброволци. Можете да допринесете с код или с коментар!
-
-Нашите дружелюбни форум членове с удоволствие ще помогнат с всеки въпрос който имаш. Поканен си да обсъждаш функции и подкастване като цяло.
-https://forum.antennapod.org/
-
-Transifex е мястото за помощ с преводите:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/bg/short-description.txt b/app/src/main/play/listings/bg/short-description.txt
deleted file mode 100644
index 1917820e6..000000000
--- a/app/src/main/play/listings/bg/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Лесен за използване, гъвкав мениджър и плейър на подкасти с отворен код \ No newline at end of file
diff --git a/app/src/main/play/listings/bg/title.txt b/app/src/main/play/listings/bg/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/bg/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/ca/full-description.txt b/app/src/main/play/listings/ca/full-description.txt
deleted file mode 100644
index 90227a4c0..000000000
--- a/app/src/main/play/listings/ca/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod és un reproductor i organitzador de podcasts que et dona accés instantani a milions de podcasts tant de pagament com gratuïts, des de podcasters independents fins a grans publicacions com la BBC, NPR i CNN. Afegeix, importa i exporta els seus feeds sense problemes usant la base de dates de podcasts de iTunes, arxius OPML o simples URLs RSS.
-Descarrega, transmet o posa en cola episodis i disfruta'ls com tu vulgues amb velocitats de reproducció ajustables, suport per a capítols i un temporitzador per a dormir.
-Estalvia esforç, bateria i us de dades mòbils amb controls d'automatització per a descarregar (hores específiques, intervals i xarxes Wi-Fi) i esborrar episodis (basant-se en els teus favorits i els ajustos de retard).
-
-Fet per entusiastes dels podcasts, AntennaPod es lliure en tots els sentits de la paraula: codi obert, sense cost, sense anuncis.
-
-<b>Importa, organitza i reprodueix</b>
-• Organitza la reproducció desde qualsevol lloc: widget a la pantalla principal, notificacions de sistema i controls d'auricular amb fil o bluetooth.
-• Afegeix i importa feeds via iTunes, gPodder.net, fitxers OPML o enllaços RSS o Atom.
-• Disfruta escoltant a la teua manera amb velocitat de reproducció ajustable, suport per a capitols, memòria de posició de reproducció i un avançat temporitzador per a dormir (que pots resetetjar agitant el mòbil)
-• Accedix a feeds i episodis protegits amb contrasenya
-
-<b>Organitza, comparteix i aprecia</b>
-• Recorda als millors dels millors marcant episodis com a favorits.
-• Troba un episodi usant el historial de reproducció o buscant títols i notes.
-• Comparteix episodis i feeds a través d'opcions avançades de medis socials i email, els serveis de gPodder.net i via l'exportació OPML.
-
-<b>Controla el sistema</b>
-• Pren control de les descarregues automàtiques: tria feeds, exclou xarxes mòbils, selecciona xarxes WiFi específiques, requereix que el telèfon estiga carregant i selecciona hores o intervals.
-• Gestioneu l'emmagatzematge ajustant la quantitat d'episodis en emmagatzematge temporal, l'esborrat intel·ligent i triant la vostra ubicació preferida.
-• Adapteu-vos al vostre entorn fent servir el tema clar o el fosc.
-• Feu còpies de seguretat de les vostres subscripcions amb la integració amb gPodder.net i l'exportació a OPML.
-
-<b>Uniu-vos a la comunitat d'AntennaPod!</b>
-L'AntennaPod el desenvolupen voluntaris. Podeu col·laborar, amb codi o comentaris.
-
-Els amigables membres del nostre fòrum estaran contents d'ajudar-vos amb qualsevol pregunta. Esteu convidats a parlar de les features i de podcasting en general, a més.
-https://forum.antennapod.org/
-
-Transifex és el lloc on podeu ajudar amb les traduccions.
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/ca/short-description.txt b/app/src/main/play/listings/ca/short-description.txt
deleted file mode 100644
index 25b884d1b..000000000
--- a/app/src/main/play/listings/ca/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Reproductor i organitzador de podcasts, fàcil d'usar, flexible i de codi obert. \ No newline at end of file
diff --git a/app/src/main/play/listings/ca/title.txt b/app/src/main/play/listings/ca/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/ca/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/cs-CZ/full-description.txt b/app/src/main/play/listings/cs-CZ/full-description.txt
deleted file mode 100644
index dc71e754c..000000000
--- a/app/src/main/play/listings/cs-CZ/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod je správce a přehrávač podcastů, co vám umožňuje okamžitý přístup k milionům podcastů (placené i zdarma) od nezávislých autorů, přes velké zahraniční korporace jako BBC, NPR a CNN, až po české DVTV nebo Český rozhlas. Své podcasty můžete jednoduše přidávat, importovat i exportovat pomocí iTunes, OPML souborů nebo RSS.
-Stahujte, streamujte nebo si vytvořte frontu epizod a užijte si poslech tak, jak ho máte rádi s nastavitelnou rychlostí přehrávání, podporou kapitol a s časovačem vypnutí.
-Ušetři si námahu, baterku i mobilní data s pomocí robustní automatické kontroly nad stahováním epizod (urči časy, intervaly a WIFI sítě) a mazáním epizod (na základě oblíbenosti a nastavení zpoždění).
-
-Vytvořeno nadšenci do podcastů, AntennaPod je software s otevřeným zdrojovým kódem, zdarma a bez reklam.
-
-<b>Importujte, organizujte a přehrávejte</b>
-• Ovládejte přehrávání odkudkoli: z widgetu na domovské obrazovce, z oznámení nebo pomocí tlačítek na sluchátkách včetně Bluetooth
-• Přidejte a importujte podcasty přes iTunes anebo gPodder.net, OPML soubory a RSS anebo Atom odkazy
-• Užijte si poslech s nastavitelnou rychlostí přehrávání, podporou kapitol, zapamatování poslední pozice přehrávání a pokročilým časovačem vypnutí (restart zatřesením, snížení hlasitosti)
-• Přistupujte k zaheslovaným podcastům a epizodám
-
-<b>Udržovat přehled, sdílet & ocenit</b>
-• Udržujte si seznam toho nejlepšího z nejlepšího přidáním epizod do oblíbených
-• Vyhledej tu správnou epizodu ve své historii přehrávání nebo prohledáním jmen a popisů epizod
-• Sdílej epizody a kanály pomocí pokročilých nastavení pro sociální média a email, gPodder.net službu nebo OPML export
-
-<b>Ovládat systém</b>
-• Převezmi kontrolu nad automatickým stahováním: vybírej kanály, vyluč mobilní sítě, vyber specifické WIFI sítě, vyžaduj stav nabíjení telefonu a nastav časy nebo intervaly
-• Spravujte využití úložiště nastavením množství uložených epizod, chytrého mazání a výběrem místa uložení
-• Přizpůsobte si aplikaci svému prostředí pomocí světlého nebo tmavého motivu
-• Zálohujte své sbírky pomocí služby gPodder.net nebo exportem OPML souborů
-
-<b>Přidejte se ke komunitě AntennaPod!</b>
-AntennaPod je aktivně vyvíjen dobrovolníky. Můžete přispět také svým kódem nebo komentáři!
-
-Naše přátelská členská základna vám ráda zodpoví jakékoli dotazy. Zveme vás k diskuzi o AntennaPodu nebo i podcastech obecně.
-https://forum.antennapod.org/
-
-Na Transifexu můžete pomoct s překladem:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/cs-CZ/short-description.txt b/app/src/main/play/listings/cs-CZ/short-description.txt
deleted file mode 100644
index e0df116ee..000000000
--- a/app/src/main/play/listings/cs-CZ/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Jednoduchý a flexibilní open-source program pro správu a poslech podcastů \ No newline at end of file
diff --git a/app/src/main/play/listings/cs-CZ/title.txt b/app/src/main/play/listings/cs-CZ/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/cs-CZ/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/da-DK/full-description.txt b/app/src/main/play/listings/da-DK/full-description.txt
deleted file mode 100644
index eb443e5d2..000000000
--- a/app/src/main/play/listings/da-DK/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod er en podcast-app der giver dig øjeblikkelig adgang til millioner af gratis og betalte podcasts, fra selvstændige udgivere til store medievirksomheder som BBC, NPR og CNN. Tilføj, importér og eksportér deres feeds uden bøvl ved brug af iTunes-podcastdatabasen, OPML-filer eller simple RSS-adresser.
-Hent, stream eller sæt afsnit i kø og nyd dem, som du vil med justerbar afspilningshastighed, kapitelunderstøttelse og automatisk slukkefunktion.
-Spar kræfter, batteristrøm og mobildataforbrug med effektive automatiseringsfunktioner til download af afsnit (angiv tidspunkter og WiFi-netværker) og sletning af afsnit (baseret på dine favoritter og indstillinger for forsinkelse).
-
-AntennaPod er lavet af podcast-entusiaster og er fri og gratis i alle betydninger: åben kildekode, gratis, ingen reklamer.
-
-<b>Importér, organiser og afspil</b>
-• Håndter afspilning fra hvor som helst: widget på startsskærmen, systemnotifikation, samt hovedtelefon og bluetooth-styring
-• Tilføj og importer feeds via iTunes- og gPodder.net-oversigter, OPML-filer og RSS- eller Atom-links
-• Nyd at lytte på din måde ved at justere afspilningshastighed, kapitelunderstøttelse, huske hvor langt du lyttede sidst og avancerede søvntimer (ryst for at starte igen, sænk lydstyrken)
-• Tilgå adgangskodebeskyttede feeds og afsnit
-
-<b>Følge med, del & værdsæt</b>
-• Hold styr på de bedste af de bedste ved at markere afsnit som foretrukne.
-• Find et bestemt afsnit gennem afspilningshistorikken eller ved at søge i titler og beskrivelser
-• Del afsnit og feeds gennem avancerede sociale medier og e-mail-muligheder, gPodder.net-tjenesterne og OPML-eksport
-
-<b>Kontroller systemet</b>
-• Tag styringen over automatiserede overførsler: Vælg feeds, udeluk mobile netværk, vælg specifikke wi-fi-netværk, kræv at telefonen oplader og indstil tider eller intervaller
-Håndter hukommelse ved at indstille antallet af afsnit der gemmes, smart sletning og din foretrukne lokation
-Tilpas app'en til dit miljø med det lyse eller mørke tema
-Backup dine abonnementer med gpodder.net integreationen og OPML-eksport
-
-<b>Kom med i AntennaPod-fællesskabet!</b>
-AntennaPod er under aktiv udvikling af frivillige. Du kan også bidrage, enten med kode eller kommentarer!
-
-Vores venlige forummedlemmer vil gerne hjælpe med ethvert spørgsmål du skulle have. Du er også velkommen til at diskutere funktionalitet og podcasts generelt.
-https://forum.antennapod.org/
-
-Transifex er stedet hvor du kan hjælpe med at oversætte:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/da-DK/short-description.txt b/app/src/main/play/listings/da-DK/short-description.txt
deleted file mode 100644
index 90cdfa8ac..000000000
--- a/app/src/main/play/listings/da-DK/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Brugervenlig, fleksibel og open source podcast-manager og afspiller \ No newline at end of file
diff --git a/app/src/main/play/listings/da-DK/title.txt b/app/src/main/play/listings/da-DK/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/da-DK/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/de-DE/full-description.txt b/app/src/main/play/listings/de-DE/full-description.txt
deleted file mode 100644
index 4563e3119..000000000
--- a/app/src/main/play/listings/de-DE/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod ist ein Podcast-Manager und -Player, mit dem Du direkten Zugriff auf Millionen von freien und kostenpflichtigen Podcasts hast, von unabhängigen Podcastern bis zu großen Rundfunkanstalten oder Hörfunksendern wie BBC, NPR und CNN. Abonniere, importiere und exportiere deine Feeds mühelos mit Hilfe des iTunes-Podcast-Verzeichnisses, OPML-Dateien oder RSS-URLs.
-Downloade, streame oder sortiere Episoden in der Abspielliste und genieße sie mit einstellbarer Wiedergabegeschwindigkeit, Unterstützung von Kapiteln und Schlummerfunktion.
-Reduziere Aufwand, Stromverbrauch und Datenverbrauch durch leistungsfähige Kontrolle der Downloads (bestimmte Uhrzeiten, Intervalle, WiFi-Netze) und des Löschens (basierend auf deinen Favoriten und weiteren Einstellungen).
-
-AntennaPod ist von Podcast-Enthusiasten gemacht und frei im wahrsten Sinne des Wortes: Open Source, keine Kosten, keine Werbung.
-
-<b>Importiere, organisiere und spiele ab</b>
-• Bediene die Wiedergabe von überall: Startbildschirm-Widget, Benachrichtigung und Kopfhörer- und Bluetooth-Bedienelemente
-• Füge Feeds über iTunes und gPodder.net oder über OMPL Dateien und RSS oder Atom Links hinzu.
-• Genieße das Zuhören genau wie du willst - mit einstellbarer Abspielgeschwindigkeit, der Unterstützung von Kapiteln und ausgereifter Schlummerfunktion (durch Schütteln zurücksetzen, Lautstärke verringern)
-• Greife auf Passwort-geschützte Feeds und Episoden zu
-
-<b>Behalte den Überblick</b>
-• Behalte den Überblick über die Besten der Besten, indem du Episoden als Favoriten markierst
-• Finde Episoden durch die Liste zuletzt gespielter Episoden oder durch Suche in Titel und Shownotes
-• Teile Episoden and Feeds über soziale Medien, E-Mail, den gPodder.net-Dienst oder als OPML-Export
-
-<b>Behalte die Kontrolle</b>
-• Kontrolliere automatisches Herunterladen: Wähle Feeds aus, schließe mobile Netze aus, suche bestimmte WiFi-Netze aus, setze voraus, dass das Smartphone geladen wird und lege Zeitpunkte oder Intervalle fest
-• Verwalte deinen Speicherplatz durch das Festlegen der Anzahl gespeicherter Episoden, schlaues Löschen und durch Auswahl des Speicherortes
-• Passt sich deiner Umgebung mit dem hellen oder dunklen Theme an
-• Sichere deine Abonnements mit gPodder.net oder über den OPML-Export
-
-<b>Tritt der AntennaPod-Community bei!</b>
-AntennaPod wird aktiv von Freiwilligen weiterentwickelt. Auch du kannst bei der Entwicklung mit Quellcode oder Kommentaren mitwirken!
-
-Unsere freundlichen Freiwilligen im Forum stehen dir bei allen Fragen zur Seite. Gerne kannst du dich dort auch über neue Funktionen und über Podcasting generell austauschen.
-https://forum.antennapod.org/
-
-Mit Transifex kannst du uns beim Übersetzen helfen:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/de-DE/graphics/large-tablet-screenshots/tablet.png b/app/src/main/play/listings/de-DE/graphics/large-tablet-screenshots/tablet.png
deleted file mode 100644
index 5ff81f1e0..000000000
--- a/app/src/main/play/listings/de-DE/graphics/large-tablet-screenshots/tablet.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/de-DE/graphics/phone-screenshots/00.png b/app/src/main/play/listings/de-DE/graphics/phone-screenshots/00.png
deleted file mode 100644
index b45199a32..000000000
--- a/app/src/main/play/listings/de-DE/graphics/phone-screenshots/00.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/de-DE/graphics/phone-screenshots/01.png b/app/src/main/play/listings/de-DE/graphics/phone-screenshots/01.png
deleted file mode 100644
index e7bfdc2d7..000000000
--- a/app/src/main/play/listings/de-DE/graphics/phone-screenshots/01.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/de-DE/graphics/phone-screenshots/02.png b/app/src/main/play/listings/de-DE/graphics/phone-screenshots/02.png
deleted file mode 100644
index 1d7ec8bf7..000000000
--- a/app/src/main/play/listings/de-DE/graphics/phone-screenshots/02.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/de-DE/graphics/phone-screenshots/03.png b/app/src/main/play/listings/de-DE/graphics/phone-screenshots/03.png
deleted file mode 100644
index 7a7ede191..000000000
--- a/app/src/main/play/listings/de-DE/graphics/phone-screenshots/03.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/de-DE/graphics/phone-screenshots/04.png b/app/src/main/play/listings/de-DE/graphics/phone-screenshots/04.png
deleted file mode 100644
index 2120934c9..000000000
--- a/app/src/main/play/listings/de-DE/graphics/phone-screenshots/04.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/de-DE/graphics/phone-screenshots/05.png b/app/src/main/play/listings/de-DE/graphics/phone-screenshots/05.png
deleted file mode 100644
index 1eedf13f9..000000000
--- a/app/src/main/play/listings/de-DE/graphics/phone-screenshots/05.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/de-DE/short-description.txt b/app/src/main/play/listings/de-DE/short-description.txt
deleted file mode 100644
index cc5ca9df6..000000000
--- a/app/src/main/play/listings/de-DE/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Einfach zu benutzender und anpassbarer Open-Source Podcast-Manager \ No newline at end of file
diff --git a/app/src/main/play/listings/de-DE/title.txt b/app/src/main/play/listings/de-DE/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/de-DE/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/en-US/full-description.txt b/app/src/main/play/listings/en-US/full-description.txt
deleted file mode 100644
index bffc60cff..000000000
--- a/app/src/main/play/listings/en-US/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the Apple Podcasts database, OPML files or simple RSS URLs.
-Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer.
-Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based on your favourites and delay settings).
-
-Made by podcast-enthusiasts, AntennaPod is free in all senses of the word: open source, no costs, no ads.
-
-<b>Import, organize and play</b>
-• Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls
-• Add and import feeds via the Apple Podcasts, gPodder.net, fyyd or Podcast Index directories, OPML files and RSS or Atom links
-• Enjoy listening your way with adjustable playback speed, chapter support, remembered playback position and an advanced sleep timer (shake to reset, lower volume)
-• Access password-protected feeds and episodes
-
-<b>Keep track, share & appreciate</b>
-• Keep track of the best of the best by marking episodes as favourites
-• Find that one episode through the playback history or by searching titles and shownotes
-• Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export
-
-<b>Control the system</b>
-• Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals
-• Manage storage by setting the amount of cached episodes, smart deletion and selecting your preferred location
-• Adapt to your environment using the light and dark theme
-• Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-Our friendly forum members are happy to help with every question you have. You are invited to discuss features and podcasting in general, too.
-https://forum.antennapod.org/
-
-Transifex is the place to help with translations:
-https://www.transifex.com/antennapod/antennapod
diff --git a/app/src/main/play/listings/en-US/graphics/feature-graphic/feature-graphic.png b/app/src/main/play/listings/en-US/graphics/feature-graphic/feature-graphic.png
deleted file mode 100644
index 2e3f60b98..000000000
--- a/app/src/main/play/listings/en-US/graphics/feature-graphic/feature-graphic.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/en-US/graphics/icon/icon.png b/app/src/main/play/listings/en-US/graphics/icon/icon.png
deleted file mode 100644
index c20627c1a..000000000
--- a/app/src/main/play/listings/en-US/graphics/icon/icon.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/en-US/graphics/large-tablet-screenshots/tablet.png b/app/src/main/play/listings/en-US/graphics/large-tablet-screenshots/tablet.png
deleted file mode 100644
index 2defb5ce9..000000000
--- a/app/src/main/play/listings/en-US/graphics/large-tablet-screenshots/tablet.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/en-US/graphics/phone-screenshots/00.png b/app/src/main/play/listings/en-US/graphics/phone-screenshots/00.png
deleted file mode 100644
index 26779f5a1..000000000
--- a/app/src/main/play/listings/en-US/graphics/phone-screenshots/00.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/en-US/graphics/phone-screenshots/01.png b/app/src/main/play/listings/en-US/graphics/phone-screenshots/01.png
deleted file mode 100644
index 9877ebba6..000000000
--- a/app/src/main/play/listings/en-US/graphics/phone-screenshots/01.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/en-US/graphics/phone-screenshots/02.png b/app/src/main/play/listings/en-US/graphics/phone-screenshots/02.png
deleted file mode 100644
index 6f938629b..000000000
--- a/app/src/main/play/listings/en-US/graphics/phone-screenshots/02.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/en-US/graphics/phone-screenshots/03.png b/app/src/main/play/listings/en-US/graphics/phone-screenshots/03.png
deleted file mode 100644
index 550c49031..000000000
--- a/app/src/main/play/listings/en-US/graphics/phone-screenshots/03.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/en-US/graphics/phone-screenshots/04.png b/app/src/main/play/listings/en-US/graphics/phone-screenshots/04.png
deleted file mode 100644
index 6d0585ff4..000000000
--- a/app/src/main/play/listings/en-US/graphics/phone-screenshots/04.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/en-US/graphics/phone-screenshots/05.png b/app/src/main/play/listings/en-US/graphics/phone-screenshots/05.png
deleted file mode 100644
index ebdf4c832..000000000
--- a/app/src/main/play/listings/en-US/graphics/phone-screenshots/05.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/en-US/graphics/tv-banner/tv-banner.png b/app/src/main/play/listings/en-US/graphics/tv-banner/tv-banner.png
deleted file mode 100644
index 142aa4839..000000000
--- a/app/src/main/play/listings/en-US/graphics/tv-banner/tv-banner.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/en-US/short-description.txt b/app/src/main/play/listings/en-US/short-description.txt
deleted file mode 100644
index acf136ae9..000000000
--- a/app/src/main/play/listings/en-US/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Easy-to-use, flexible and open-source podcast manager and player
diff --git a/app/src/main/play/listings/en-US/title.txt b/app/src/main/play/listings/en-US/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/en-US/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/es-ES/full-description.txt b/app/src/main/play/listings/es-ES/full-description.txt
deleted file mode 100644
index 52897ce9c..000000000
--- a/app/src/main/play/listings/es-ES/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod es un gestor y reproductor de podcasts que te da acceso instantáneo a millones de podcast gratuitos y de pago; desde podcasters independientes a grandes estaciones como la BBC, NPR y CNN. Agrega, importa y exporta las fuentes de manera sencilla usando el listado de iTunes, archivos OPML o las URL de tipo RSS. Ahorra esfuerzo, batería y datos con los controles de descarga y de borrado de episodios (basado en favoritos y ajustes de tiempo).
-Descarga, escucha en stream o añade a la cola episodios y disfrútalos como quieras con velocidad de reproducción ajustable, soporte para capítulos y temporizador de sueño.
-Ahorra esfuerzo, batería y consumo de datos con los potentes controles de automatización para descarga (especifica la hora y desde qué redes Wi-Fi) y el borrado de episodios antiguos (basado en tus preferencias).
-
-Creado por entusiastas del pódcast, AntennaPod es libre en todos los sentidos: código abierto, gratuito y sin publicidad.
-
-<b>Importar, organizar y reproducir</b>
-• Administra la reproducción desde cualquier parte: control en la pantalla de inicio, las notificaciones del sistema y los controles de auriculares y bluetooth
-• Añade e importa fuentes mediante los directorios de iTunes y gPodder.net, archivos OPML y enlaces RSS o Atom
-• Disfruta escuchando a tu manera, con velocidad de reproducción ajustable, soporte de capítulos (MP3, VorbisComment y Podlove), marcador del punto de reproducción y temporizador de sueño avanzado (agita para restablecer, bajar el volumen y disminuir la velocidad de reproducción)
-• Accede a fuentes y episodios protegidos con contraseña
-
-<b>Seguir, valorar y compartir </b>
-• Haz un seguimiento de lo mejor de lo mejor marcando episodios como favoritos
-• Busca ese episodio en el historial o busca por título y notas
-• Comparte episodios y fuentes a través de las opciones avanzadas de redes sociales y correo electrónico, los servicios de gPodder.net y exportando a OPML
-
-<b>Control del sistema</b>
-• Controla las descargas automáticas: elige las fuentes, excluye las redes móviles, selecciona redes WiFi específicas, cuando el teléfono se cargue, establece horarios o intervalos
-• Gestiona el almacenamiento configurando la cantidad de episodios en caché, borrado inteligente y eligiendo tu ubicación favorita
-• Adáptate a tu entorno usando el tema claro u oscuro
-• Haz una copia de seguridad de tus suscripciones con la integración de gPodder.net y exportando a OPML
-
-<b>¡Únete a la comunidad AntennaPod!</b>
-AntennaPod es desarrollado por voluntarios. ¡Tú también puedes contribuir, con tu código o con tus comentarios!
-
-Nuestros amables miembros del foro te ayudarán con cualquier duda que tengas. Estás invitado a discutir sobre las características y el podcasting en general.
-https://forum.antennapod.org/
-
-Ayuda con las traducciones en Transifex:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/es-ES/graphics/phone-screenshots/00.png b/app/src/main/play/listings/es-ES/graphics/phone-screenshots/00.png
deleted file mode 100644
index 6c3ed9122..000000000
--- a/app/src/main/play/listings/es-ES/graphics/phone-screenshots/00.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/es-ES/graphics/phone-screenshots/01.png b/app/src/main/play/listings/es-ES/graphics/phone-screenshots/01.png
deleted file mode 100644
index 7bd0730a4..000000000
--- a/app/src/main/play/listings/es-ES/graphics/phone-screenshots/01.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/es-ES/graphics/phone-screenshots/02.png b/app/src/main/play/listings/es-ES/graphics/phone-screenshots/02.png
deleted file mode 100644
index 2c02ee1d5..000000000
--- a/app/src/main/play/listings/es-ES/graphics/phone-screenshots/02.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/es-ES/graphics/phone-screenshots/03.png b/app/src/main/play/listings/es-ES/graphics/phone-screenshots/03.png
deleted file mode 100644
index 306de8f3b..000000000
--- a/app/src/main/play/listings/es-ES/graphics/phone-screenshots/03.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/es-ES/graphics/phone-screenshots/04.png b/app/src/main/play/listings/es-ES/graphics/phone-screenshots/04.png
deleted file mode 100644
index c1a09170c..000000000
--- a/app/src/main/play/listings/es-ES/graphics/phone-screenshots/04.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/es-ES/graphics/phone-screenshots/05.png b/app/src/main/play/listings/es-ES/graphics/phone-screenshots/05.png
deleted file mode 100644
index 2698d5d27..000000000
--- a/app/src/main/play/listings/es-ES/graphics/phone-screenshots/05.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/es-ES/short-description.txt b/app/src/main/play/listings/es-ES/short-description.txt
deleted file mode 100644
index cc94d9c22..000000000
--- a/app/src/main/play/listings/es-ES/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Reproductor y gestor de pódcast fácil de usar, flexible y de código abierto \ No newline at end of file
diff --git a/app/src/main/play/listings/es-ES/title.txt b/app/src/main/play/listings/es-ES/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/es-ES/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/et/full-description.txt b/app/src/main/play/listings/et/full-description.txt
deleted file mode 100644
index 7b7da2a4e..000000000
--- a/app/src/main/play/listings/et/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod on taskuhäälingu haldur ja esitaja, millega saad kohe ligipääsu miljonitele tasuta ja tasulistele saadetele nii ise- kui suurtegijatelt nagu BBC, NPR ja CNN. Lisa, impordi ja ekspordi nende voogusid ilma probleemideta, kasutades iTunes'i taskuhäälingute andmebaasi, OPML faili või lihtsalt RSS URL-e.
-Laadi alla, voogedasta või lisa kuulamise järjekorda saateid ning naudi neid täpselt nii, nagu sina tahad, kasutades muudetavat taasesituse kiirust, peatükkide tuge ja unetaimerit.
-Säästa pingutuselt, aku kestuselt ja mobiilse andmeside kasutuselt võimekate automatiseerimise vahenditega saadete allalaadimiseks (määra millal, mis sagedusega ja millistes WiFi võrkudes) ning kustutamiseks (vastavalt sinu lemmikutele ja viivituse sätetele).
-
-Kuna AntennaPod on tehtud taskuhäälingu entusiastide poolt, on AntennaPod vaba selle sõna igas tähenduses: vaba lähtekoodiga, tasuta ja ilma mingi reklaamita.
-
-<b>Impordi, korrasta ja kuula</b>
-• Halda esitust kust tahes: avaekraani vidina abil, süsteemi teate kaudu või kõrvaklappide või bluetoothi nuppude abil
-• Lisa ja impordi voogusid iTunesi ja gPodder.net kaustadest, OPML failidest ja RSS või Atom linkide kaudu
-• Naudi kuulamist just sinu moodi tänu muudetavale esituskiirusele, peatükkide toele, meeldejäetavale asukohale ning unetaimerile (raputamine, valjuse vähendamine)
-• Ligipääs parooliga kaitstud voogudele ja saadetele
-
-<b>Talleta ja jaga, et avaldada tunnustust</b>
-• Talleta parimatest parimaid märkides saateid lemmikuteks
-• Leia see üks saade otsides esitatute ajaloost pealkirjade või kirjelduste järgi
-• Jaga saateid ja voogusid suurepäraste sotsiaalmeedia ja e-posti valikute abil, gPodder.neti kaudu ja OPML failide abil
-
-<b>Oma kontrolli</b>
-• Võta kontroll automaatse allalaadimise üle enda kätte: vali vood, keela mobiilivõrk, vali õiged WiFi võrgud, ütle, kui telefon peaks allalaadimise ajal laadima või määra millal ja kui tihti saateid alla laadida
-• Halda ruumikasutust, määrates mitu saadet varuks hoida, luba nutikas kustutamine ja failide eelistatud asukoha määramine
-• Kohanda keskonnaga heleda ja tumeda kujundusega
-• Varunda oma tellimused gPodder.net keskkonda ja OPML faili eksportides
-
-<b>Liitu AntennaPodi kogukonnaga!</b>
-AntennaPod on vabatahtlike poolt aktiivselt arendamisel. Ka sina võid anda oma osa, kirjutades koodi või andes tagasisidet!
-
-Meie sõbralikud foorumi liikmed aitavad sind meeleldi leida vastuse kõigile küsimustele. Oled oodatud arutama nii äpi võimalusi kui taskuhäälinguid üldiselt.
-https://forum.antennapod.org/
-
-Transifex on koht, kus saab aidata tõlgetega:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/et/short-description.txt b/app/src/main/play/listings/et/short-description.txt
deleted file mode 100644
index 59ff4ac69..000000000
--- a/app/src/main/play/listings/et/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Lihtne, paindlik ja avatud lähtekoodiga taskuhäälingu haldur ja esitaja \ No newline at end of file
diff --git a/app/src/main/play/listings/et/title.txt b/app/src/main/play/listings/et/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/et/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/eu-ES/full-description.txt b/app/src/main/play/listings/eu-ES/full-description.txt
deleted file mode 100644
index e64861475..000000000
--- a/app/src/main/play/listings/eu-ES/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod podcast kudeatzaile eta erreproduzigailua da, eta berehalako sarbidea ematen dizu doako eta ordainpeko milioika podcast-etara, podcaster independenteetatik BBC, NPR eta CNN bezalako estazio handietara. Iturriak modu errazean gehitu, inportatu eta esportatzen ditu, iTunesen, OPML fitxategien edo RSS motako URLen zerrenda erabiliz. Esfortzua, bateria eta datuak aurrezten ditu gertaeren deskarga- eta ezabatze-kontrolekin (gogokoetan eta denbora-doikuntzetan oinarrituta).
-Deskargatu, stream-ean entzun, edo gehitu saioak ilaran eta goza itzazu nahi bezala erreprodukzio abiadura doigarriarekin, kapituluetarako euskarria eta lo-tenporizadorearekin.
-Aurreztu lana, bateria eta datu-kontsumoa deskargatzeko automatizazio-kontrol indartsuekin (zehaztu zein ordutan eta zein Wi-Fi saretatik) eta ezabatu antzinako gertakariak (zure lehentasunetan oinarrituta).
-
-Podcastaren jarraitzaile sutsuek sortua, AntennaPod askea da zentzu guztietan: kode irekia, doakoa eta publizitaterik gabekoa.
-
-<b>Inportatu, antolatu eta erreproduzitu</b>
-Erreprodukzioa edozein lekutatik administratzen du: kontrola hasierako pantailan, sistemaren jakinarazpena eta aurikular eta bluetooth kontrolak
-Iturriak gehitu eta inportatu iTunes eta gPodder.net direktorio eta, OPML artxiboen eta RSS edo Atom esteken bidez
-& # 8226; Zure erara entzunez gozatu erreprodukzio-abiadura doigarriaz, kapituluen euskarria (MP3, VorbisComment eta Podlove), erreprodukzio-puntuaren eta loaldi aurreratuko tenporizadorearen oroigarria (astindu bolumena berrezartzeko, jaisteko eta erreprodukzio-abiadura murrizteko <br>
-• pasahitzarekin babestutako iturrietan eta saioetan sartu
-
-<b>Jarraitu, baloratu eta partekatu</b>
-• egin onenetan onenen segimendua saioak gogokoetan sartuz
-• Aurkitu saio hori erreprodukzioaren historialaren bidez edo bilaketa bidez(atalen izenburuak eta oharrak)
-• Saioak eta iturriak partekatu sare sozial aurreratuen bidez eta posta elektroniko, gPodder.net zerbitzu eta OPML esportazioaren bidez
-
-<b>Sistemaren kontrola</b>
-• Deskarga automatikoak kontrolatu: iturriak aukeratu, sare mugikorrak baztertu, wifi sare espezifikoak hautatu, edo telefonoa kargatzen ari denean bakarrik egin, eta ordutegiak edo tarteak ezarri
-• Biltegiratzea kudeatu, cache-ko gertakari-kopurua konfiguratu, ezabatu adimenduna konfiguratu eta zure kokaleku gustukoena aukeratu
-• Zure ingurura egokitu gai argia edo iluna erabiliz
-• Zure harpidetzen segurtasun-kopia bat egin, gPodder.net eta OPML esportazio integratua erabiliz
-
-<b>Bat egin AntennaPod komunitatearekin!</b>
-AntennaPod etengabe ari da garatzen boluntarioekin. Zuk ere ekarpena egin dezakezu, zure kodearekin edo zure iruzkinekin!
-
-Foroko kideak pozik daude galdera bakoitzarekin laguntzeagatik. Ezaugarriak eta podcastinga, oro har, eztabaidatzera gonbidatuta zaude.
-https://forum.antennapod.org/
-
-Transifex itzulpenekin laguntzeko lekua da:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/eu-ES/short-description.txt b/app/src/main/play/listings/eu-ES/short-description.txt
deleted file mode 100644
index 696e613fc..000000000
--- a/app/src/main/play/listings/eu-ES/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Erabiltzeko erraza, malgua eta kode irekikoa den podcast erreproduzitzailea \ No newline at end of file
diff --git a/app/src/main/play/listings/eu-ES/title.txt b/app/src/main/play/listings/eu-ES/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/eu-ES/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/fa/full-description.txt b/app/src/main/play/listings/fa/full-description.txt
deleted file mode 100644
index 7148fac55..000000000
--- a/app/src/main/play/listings/fa/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-کاره‌ٔ آنتناپاد، مدیر و پخش‌کنندهٔ پادکستی است که امکان دسترسی سریع به میلیون‌ها پادکست رایگان و پولی، از افراد مستقل تا تولیدکنندگان بزرگ مانند بی‌بی‌سی و سی‌ان‌ان را می‌دهد. با استفاده از پایگاه دادهٔ آی‌تونر، پرونده‌های OPML یا نشانی‌های سادهٔ RSS، بدون دردسر خوراک‌هایشان را افزوده و آن‌ها را درون‌ریزی و برون‌ریزی کنید.
-قسمت‌ها را بارگیری، پخش جریانی یا صف‌بندی کرده و با سرعت‌های پخش قابل تنظیم، پشتیبانی از فصل‌ها و زمان‌سنج خواب، هرطور دوست دارید، از آن‌ها لذّت ببرید.
-با بارگیری خودکار برای بارگیری قسمت ها (زمان ها ، بازه ها و شبکه های WiFi) و حذف قسمت ها (بر اساس موارد دلخواه و تنظیمات تأخیری) ، در مصرف باتری و استفاده از حجم مصرفی داده های تلفن همراه صرفه جویی کنید.
-
-AntennaPod ساخته شده توسط علاقه مندان به پادکست ، به تمام معنا رایگان است: منبع باز ، بدون هزینه ، بدون تبلیغات.
-
-<b>درون‌ریزی، سازمان‌دهی و پخش</b>
-• پخش را از هر کجا مدیریت کنید: ویجت صفحه اصلی ، اعلان سیستم و کنترل گوش و بلوتوث
-• افزودن و وارد کردن فیدها از طریق دایرکتوری های iTunes و gPodder.net ، فایل های OPML و پیوندهای RSS یا Atom
-• با تنظیم سرعت پخش ، پشتیبانی فصل ، به خاطر سپرده شدن موقعیت پخش و یک تایمر خواب پیشرفته (لرزش برای تنظیم مجدد ، کاهش صدا) از گوش دادن به پادکست لذت ببرید.
-• دسترسی به قسمت‌ها و خوراک‌های محافظت‌شده با گذرواژه
-
-پیگیری کنید ، به اشتراک بگذارید و قدردانی کنید
-• با علامت گذاری قسمت ها به عنوان موارد دلخواه ، بهترین بهترینها را دنبال کنید
-• قسمت مورد نظر خود را از طریق سابقه پخش یا با جستجوی عنوانها و نشانهای موجود پیدا کنید
-• قسمت ها و فیدها را از طریق رسانه های اجتماعی پیشرفته و گزینه های ایمیل ، خدمات gPodder.net و از طریق صادرات OPML به اشتراک بگذارید
-
-<b>کنترل سامانه</b>
-• کنترل بارگیری خودکار را در دست بگیرید: فیدها را انتخاب کنید ، شبکه های WiFi خاصی را انتخاب کنید و شبکه های تلفن همراه را برای بارگیری معاف کنید. همچنین مسخص کنید که بارگیری نیاز به وصل بودن تلفن به شارژ داشته باشد و زمان یا فاصله زمانی را تنظیم کنید
-با تنظیم میزان قسمت های ذخیره شده ، حذف هوشمند و انتخاب مکان دلخواه خود ، ذخیره سازی را مدیریت کنید
-• با استفاده از تم روشن و تیره با محیط خود سازگار شوید
-• از اشتراک های خود با ادغام gPodder.net و صادرات OPML پشتیبان بگیرید
-
-<b>به اجتماع AntennaPod بپیوندید!</b>
-برنامه AntennaPod توسط گروهی از افراد داوطلب در حال توسعه فعال است. شما نیز می‌توانید با کدنویسی و یا نظر دادن، در روند توسعه مشارکت کنید.
-
-اعضای انجمن دوستانه ما خوشحال می شوند که در هر سوالی کمک کنند. همچنین از شما دعوت می شود تا درباره ویژگی ها و پادکست به طور کلی بحث کنید.
-https://forum.antennapod.org/
-
-برای کمک به ترجمه می‌توانید از Transifex استفاده کنید:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/fa/short-description.txt b/app/src/main/play/listings/fa/short-description.txt
deleted file mode 100644
index 4085269cb..000000000
--- a/app/src/main/play/listings/fa/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-مدیر و پخش‌کنندهٔ پادکست، با کاربری آسان، منعطف و متن‌باز \ No newline at end of file
diff --git a/app/src/main/play/listings/fa/title.txt b/app/src/main/play/listings/fa/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/fa/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/fi-FI/full-description.txt b/app/src/main/play/listings/fi-FI/full-description.txt
deleted file mode 100644
index 9b7ea0df1..000000000
--- a/app/src/main/play/listings/fi-FI/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod on podcastien hallintaan ja toistoon luotu sovellus, joka mahdollistaa pääsyn miljooniin ilmaisiin ja maksullisiin podcasteihin itsenäisistä podcast-tuottajista suuriin julkaisijoihin, kuten BBC, NPR ja CNN. Lisää, tuo ja vie syötteitä vaivattomasti iTunesin podcast-tietokantaa, OPML-tiedostoja tai yksinkertaisia RSS-osoitteita käyttäen.
-Lataa, suoratoista tai lisää jonoonjaksoja ja nauti niitä säädettävällä toistonopeudella, kappaletuella ja uniajastimella.
-Säästä vaivaa, akkua ja mobiilidataa tehokkailla automatisoiduilla jaksojen lataustoiminnoilla (aseta ajat, aikavälit, WiFi-verkot) ja poistotoiminnoilla (perustuen suosikkeihin ja viiveasetuksiin).
-
-Podcasteihin uppoutuneihin luoma sovellus, AntennaPod on vapaa ja ilmainen kaikissa sanan merkityksissä: vapaa lähdekoodi, ei maksuja, ei mainoksia.
-
-<b>Tuo, organisoi, toista</b>
-• Hallitse toistoa mistä vain: kotinäytön pienoissovellluksesta, järjestelmän ilmoituksista, kuulokkeiden tai bluetoothin ohjaimista
-• Lisää ja tuo syötteitä iTunes- ja gPodder.net-hakemistoista, OPML-tiedostoista sekä RSS- ja Atom-linkeistä
-• Kuuntele ja nauti tavoillasi: säädettävä toistonopeus, kappaletuki, toistokohdan muistaminen ja kehittynyt uniajastin (ravista nollataksesi, matalampi äänenvoimakkuus)
-• Käytä salasanasuojattuja syötteitä ja jaksoja
-
-<b>Pysy kartalla, jaa ja arvosta</b>
-• Pysy kartalla parhaista jaksoista merkkaamalla suosikkijaksoja
-• Löydä juuri se yksi jakso toistohistorian tai hakutoiminnon kautta, joka hakee jaksojen otsikoista ja kuvauksista
-• Jaa jaksoja ja syötteitä kehittyneillä some- ja sähköpostivalinnoilla, gPodder.net-palvelulla ja OPML-viennillä
-
-<b>Hallitse järjestelmää</b>
-• Ota automaattinen lataus haltuun: valitse syötteet sekä WiFi-verkot, joissa automaattilataukset suoritetaan. Lisäksi voit poistaa lataukset käytöstä mobiiliverkossa, hakea jaksoja vain puhelimen ollessa latauksessa sekä asettaa aikavälit tai kellonajat jaksojen hakuun
-• Hallitse tallennustilaa asettamalla välimuistiin ladattujen jaksojen määrä, älykäs poisto ja latausten sijainti
-• Mukauta ympäristöösi käyttäen vaaleaa ja tummaa teemaa
-• Varmuuskopioi tilauksesi gPodder.net-integraatiolla ja OPML-viennillä
-
-<b>Liity AntennaPod-yhteisöön!</b>
-AntennaPod on vapaaehtoisten aktiivisessa kehityksessä. Sinä voit auttaa koodilla tai kommentilla!
-
-Ystävälliset foorumin jäsenet vastaavat mielellään jokaiseen kysymykseesi. Kutsumme sinut keskustelemaan myös ominaisuuksista ja podcasteista yleisesti.
-https://forum.antennapod.org/
-
-Transifex on kielikäännöksien kirjoitusalusta:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/fi-FI/short-description.txt b/app/src/main/play/listings/fi-FI/short-description.txt
deleted file mode 100644
index 4e235a7b4..000000000
--- a/app/src/main/play/listings/fi-FI/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Helppokäyttöinen, mukautuva vapaan lähdekoodin podcast-sovellus. \ No newline at end of file
diff --git a/app/src/main/play/listings/fi-FI/title.txt b/app/src/main/play/listings/fi-FI/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/fi-FI/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/fr-FR/full-description.txt b/app/src/main/play/listings/fr-FR/full-description.txt
deleted file mode 100644
index aa84179aa..000000000
--- a/app/src/main/play/listings/fr-FR/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod est un lecteur de podcast permettant l'accès à des millions de podcast gratuits ou payants produit par des podcasters indépendants ou de gros éditeurs comme la BBC, NPR, CNN. Ajoutez, importez et exportez facilement des podcasts à partir d'ITunes, de fichiers OPML ou de liens RSS.
-Téléchargez, streamez ou ajoutez à la liste de lecture vos épisodes et écoutez les comme vous aimez avec une vitesse de lecture réglable, le support des chapitres et un minuteur d'arrêt automatique.
-Economisez votre temps, votre batterie et votre consommation de données grâce à l'automatisation des téléchargements (date, fréquence, choix du réseau WiFi) et la suppression des épisodes (selon vos critères)
-
-Conçu par des fans de podcast, AntennaPod est gratuit, open source et sans publicité.
-
-<b>Importez, organisez et écoutez</b>
-• Gérez la lecture à l'aide : de widget, de notification système, de commande casque ou bluetooth
-• Ajouter et importer à partir d'iTunes, gPodder.net, de fichiers OPML, de liens RSS ou Atom
-• Ecoutez à votre façon grâce à une vitesse de lecture réglable, au support des chapitres, à l'enregistrement de la position de lecture et à un minuteur d'arrêt automatique puissant (secouez pour réinitialiser, baisse du volume)
-• Accès possible aux flux et épisodes nécessitant un mot de passe
-
-<b>Suivez, partagez et appréciez</b>
-• Enregistrez les meilleurs épisodes en tant que favoris
-• Trouvez un épisode à partir de l'historique de lecture ou en cherchant les titres et les notes/descriptions des épisodes
-• Partagez vos épisodes et flux sur les réseaux sociaux, par email, sur gPodder.net ou en les exportant au format OPML
-
-<b>Contrôlez</b>
-• Prenez le contrôle en automatisant vos téléchargements : flux spécifiques, restriction de la connexion mobile, réseaux WIFI autorisés, seulement pendant la recharge, fréquence ou heure de mise à jour
-• Gérez l'espace de stockage en réglant le nombre d'épisodes à garder, quand les supprimer et où les enregistrer
-• Adaptez l'interface selon vos préférences avec le thème clair ou sombre
-• Sauvegardez vos abonnements avec gPodder.net ou des exports OPML
-
-<b>Rejoignez la communauté d'AntennaPod !</b>
-AntennaPod est développé activement par des volontaires. Vous pouvez aussi contribuer avec du code, des traductions ou des commentaires !
-
-Les utilisateurs de notre forum seront heureux de répondre à vos questions. Rejoignez-nous pour discuter des fonctionnalités et des podcasts.
-https://forum.antennapod.org/
-
-Rendez-vous sur Transifex pour aider la traduction :
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/00.png b/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/00.png
deleted file mode 100644
index c51243a76..000000000
--- a/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/00.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/01.png b/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/01.png
deleted file mode 100644
index 58e14b540..000000000
--- a/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/01.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/02.png b/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/02.png
deleted file mode 100644
index 16d6d2f30..000000000
--- a/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/02.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/03.png b/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/03.png
deleted file mode 100644
index abbe2565e..000000000
--- a/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/03.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/04.png b/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/04.png
deleted file mode 100644
index 884d91a66..000000000
--- a/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/04.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/05.png b/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/05.png
deleted file mode 100644
index 14f04a323..000000000
--- a/app/src/main/play/listings/fr-FR/graphics/phone-screenshots/05.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/fr-FR/short-description.txt b/app/src/main/play/listings/fr-FR/short-description.txt
deleted file mode 100644
index 3214e7933..000000000
--- a/app/src/main/play/listings/fr-FR/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Un lecteur de podcast facile et souple à utiliser \ No newline at end of file
diff --git a/app/src/main/play/listings/fr-FR/title.txt b/app/src/main/play/listings/fr-FR/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/fr-FR/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/gl-ES/full-description.txt b/app/src/main/play/listings/gl-ES/full-description.txt
deleted file mode 100644
index 432677e8d..000000000
--- a/app/src/main/play/listings/gl-ES/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod é un xestor de podcast e reprodutor que che permite acceder a millóns de contidos gratuítos e de pagamento, desde produtores independentes a grandes empresas de contidos como BBC, NPR ou CNN. Engade, importa e exporta as súas fontes sen complicacións utilizando a base de datos de iTunes, ficheiros OPML ou URL de RSS.
-Descarga, difunde ou pon e cola episodios e desfrútaos do xeito que prefiras, con velocidade de reprodución axustable, soporte de capítulos e apagado programable.
-De xeito doado, aforrando batería e datos móbiles, con ferramentas potentes para a automatización das descargas (indicando horarios, intervalos e redes WiFi) e borrado de ficheiros (baseado nos favoritos e axustes temporais).
-
-Feita por entusiastas do podcast, AntennaPod é libre en todos os sentidos da palabra: código aberto, gratuíto e sen anuncios.
-
-<b>Importar, organizar e reproducir</b>
-• Controlar a reprodución desde calquera lugar: widget na pantalla, sistema de notificacións e controis de auriculares e por bluetooth.
-• Engade e importa fontes vía directorios de iTunes e gPodder.net, ficheiros OPML e ligazóns RSS ou Atom.
-• Desfruta escoitando ao teu xeito, con velocidade axustable, soporte de capítulos, lembra a posición de reprodución e programa a hora de apagado (axita para restablecer, volume máis baixo)
-• Acceso protexido con contrasinal para fontes e episodios
-
-<b>Leva un rexistro, comparte e promociona</b>
-• Mantén un rexistro dos mellores episodios marcándoos como favoritos
-• Atopa un episodio no histórico de reprodución ou buscando por títulos e notas do episodio
-• Comparte episodios e fontes a través da web social, correo electrónico, o servizo gPodder.net e exportándoos como OPML.
-
-<b>Xestiona o sistema</b>
-• Toma o control das descargas automáticas: escolle fontes, exclúe redes móbiles, redes Wifi específicas, que o móbil esté cargando ou establece horarios para a descarga
-• Xestiona a almacenaxe establecendo a número de episodios gardados, borrado intelixente e escollendo a localización preferida.
-• Adáptase ao teu entorno utilizando os decorados claro ou escuro
-• Respalda as túas subscricións con gPodder.net e a exportación OPML
-
-<b>Participa na comunidade AntennaPod!</b>
-AntennaPod está baixo continuo desenvolvemento grazas a persoas voluntarias. Ti tamén podes contribuír, con código ou con comentarios!
-
-No noso foro estamos encantados de poder axudarche con calquera dúbida que teñas. Convidámoste a comentar a aplicación e o podcasting en xeral.
-https://forum.antennapod.org/
-
-As traducións fanse en Transifex:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/gl-ES/short-description.txt b/app/src/main/play/listings/gl-ES/short-description.txt
deleted file mode 100644
index 755ae7c13..000000000
--- a/app/src/main/play/listings/gl-ES/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Xestor de podcast e reprodutor doado de utilizar, flexible e de código aberto \ No newline at end of file
diff --git a/app/src/main/play/listings/gl-ES/title.txt b/app/src/main/play/listings/gl-ES/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/gl-ES/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/hi-IN/full-description.txt b/app/src/main/play/listings/hi-IN/full-description.txt
deleted file mode 100644
index ad6145a68..000000000
--- a/app/src/main/play/listings/hi-IN/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-एण्टेन्नापोड एक संकुलप्रसारण प्रबन्धक और चालक है जो आपको तुरन्त उपलब्ध करेगा अब्जों के निःशुल्क और शुल्क युक्त संकुलप्रसारण, स्वतन्त्र संंकुलप्रसारण कर्ताओं से लेकर बडे प्रकाशन घरों जैसे बीबीसी, एनपीआर और सीएनएन। जोडें आयात करें और निर्यात करें उनके सूचियाँ बिना कठिनाई के एैट्यून्स संकुलप्रसारण तथ्यकोश अथवा रूपरेखापत्र अभिलेख अथवा अतिसरलसमूहन जालपताओं का प्रयोग करके।
-जालावरोहण करें जालसरणी चलाएँ अथवा पंक्ति में जोडें और अपने चाह अनुसार आनन्द लें अनुकूलनीय चलन गति, प्रसारण विभाजन सुविधा और विश्राम घडी के साथ।
-श्रम मात्रा विद्युतकोश और विचलनशील संचार प्रणाली का प्रयोग घटाएँ प्रबल स्वचालन नियन्त्रणों के साथ प्रसारणों की जालावरोहण के लिए ( विशेष समय अवधि और तन्तुरहित मूलनिष्ठ संचार प्रणाली का प्रयोग स्पष्ट करके ) और प्रसारणों को मिटाने के लिए ( आपके प्रिय सूची और रोक प्रबन्ध आधारित ) ।
-
-संकुलप्रसारण में रुचि रखनेवालों द्वारा बनाया हुआ। एण्टेन्नापोड सभी प्रतिबन्धों से मुक्त है। खुला क्रमलेख। निःशुल्क। विज्ञापन मुक्त।
-
-<b> आयात करें, प्रबन्ध करें और चलाएँ </b>
-• किसी स्थान से भी चलन का प्रबन्ध करें। गृहपटल प्रस्तुती भाग, यन्त्र सूचना, कर्ण स्थित ध्वनी उत्पादक अथवा नीलदन्त संचार प्रणाली के नियन्त्रणतल।
-• सूचियों जोडें और आयात करें एैट्यून्स और gPodder.net निर्देशिकाओं से अथवा रूपरेखापत्र अभिलेख और अतिसरलसमूहन अथवा आटम जालजोडों के द्वारा
-• अपने अनुकूल सुनने का आनन्द लें अनुकूलनीय चलन गति, प्रसारण विभाजन सुविधा, चलन स्थान का स्मरण और विकसित विश्राम घडी ( पुनः स्थापन के लिए हिलाएँ, ध्वनी स्तर घटाएँ ) के साथ।
-• गूढशब्द द्वारा सुरक्षित सूचियों और प्रसारणों का ग्रहण करें
-
-<b> जानकारी रखें, प्रचार करें और प्रशम्सा करें </b>
-• श्रेष्ठ में से श्रेष्ठ की जानकारी रखें प्रसारणों को प्रिय चिह्नित करके।
-• जो प्रसारण चाहिए उसे ढूण्ढ लें चलन इतिहास में से अथवा नाम और विवरण में खोजके।
-प्रसारणों और सूचियों का प्रचार करें विकसित सामाजि माध्यम, जालसम्पर्क, gPodder.net सुविधा और रूपरेखापत्र निर्यात के द्वारा।
-
-<b> समस्त का नियन्त्रण करें </b>
-• नियन्त्रण अपने हाथ में रखें स्वचलित जालावरोहण पर। सूचियाँ चुनें, विचलनशील संचार प्रणाली का प्रयोग रोकें, विशिष्ट तन्तुरहित मूलनिष्ठ संचार प्रणाली चुनें, प्रतिबन्ध लगाएँ की विद्युतकोश भर रहा हो, समय और अवधि का प्रबन्ध करके।
-• स्मरणकोश का प्रबन्ध करें अल्पकालिक स्मृत प्रसारणों की संख्या की स्थापना करके अथवा सामर्थ्य युक्त मिटाना चालू करके अथवा आपके लिए उचित अभिलेख स्थान चुनकर।
-• आपके पर्यावरण अनुसार अनुकूलित करें ज्योतिर्मय तथा तमोमय रूप शैली का प्रयोग करके।
-• आपके अनुसरण सूची का सुरक्षित अनुकरण करें gPodder.net के सहयोग से अथवा रूपरेखापत्र निर्यात से।
-
-<b> एण्टेन्नापोड समुदाय से जोडें। </b>
-एण्टेन्नापोड स्वयंसेवकों द्वारा सक्रिय विकास में है। आप भी क्रमलेख अथवा टिप्पणी के साथ योगदान दे सकते हैं।
-
-हमारे मित्रतापूर्ण विवादस्थान सदस्य आनन्दित हैं आपके सभी प्रश्न पर सहायता देने के लिए। आप आमन्त्रित हैं वाद विवाद करने के लिए विशेषताएँ अथवा सामान्य रूप में संकुलप्रसारण के विषय भी।
-https://forum.antennapod.org/
-
-ट्रान्सिफेक्स पर अनुवादों के लिए सहायता दे सकते हैं।
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/hi-IN/short-description.txt b/app/src/main/play/listings/hi-IN/short-description.txt
deleted file mode 100644
index 123f49561..000000000
--- a/app/src/main/play/listings/hi-IN/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-प्रयोग करने में सरल, अनुकूलनीय और खुला क्रमलेख का संकुलप्रसारण प्रबन्धक और चालक \ No newline at end of file
diff --git a/app/src/main/play/listings/hi-IN/title.txt b/app/src/main/play/listings/hi-IN/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/hi-IN/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/hu-HU/full-description.txt b/app/src/main/play/listings/hu-HU/full-description.txt
deleted file mode 100644
index a28bcf156..000000000
--- a/app/src/main/play/listings/hu-HU/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-Az AntennaPod egy podcastkezelő és -lejátszó, amely azonnali hozzáférést nyújt ingyenes és fizetős podcastok millióihoz: a független podcastkészítőktől kezdve a nagy kiadókig, mint a BBC, NPR és a CNN. Adjon hozzá, importáljon és exportáljon csatornákat az iTunes podcast adatbázis, OPML fájlok vagy egyszerű RSS URL-ek segítségével.
-Töltsön le, hallgassa élőben vagy állítsa sorba az epizódokat, és elvezze azokat, ahogy szeretné az állítható lejátszási sebességgel, a fejezettámogatással és az alvási időzítővel.
-Spóroljon az idejével, az akkumulátorral és a mobiladat-keretével a sokoldalú automatizálási beállításokkal, melyek letöltik az epizódokat (adjon meg időket, intervallumokat és WiFi-hálózatokat), és törlik is azokat (a kedvencei vagy a késleltetési beállításai alapján).
-
-Podcast-rajongók készítésében, az AntennaPod teljesen szabad, nyílt forráskódú, ingyenes, és hirdetésektől mentes.
-
-<b>Importálás, rendszerezés és lejátszás</b>
-• Lejátszás kezelése bárhonnan: a kezdőképernyőről, fülhallgatóról és bluetoothos vezérlőkről
-• Csatornák hozzáadása és importálása iTunesból, gPodder.net könyvtárakból, OPML-fájlokból és RSS/Atom hivatkozásokból
-• Hallgasson saját ízlése szerint az állítható lejátszási sebességgel, fejezettámogatással, megjegyzett lejátszási pozícióval és egy nagy tudású alvási időzítővel (rázás az újraindításhoz, hangerő csökkentéshez)
-• Jelszóval védett csatornák és epizódok elérése
-
-<b>Kövesse, ossza meg és élvezze</b>
-• Kövesse a legjobbak legjobbját azáltal, hogy kedvencként jelöli meg az epizódokat
-• Találja meg azt a bizonyos epizódot a lejátszási előzményekkel vagy cím és adásjegyzetek alapján történő kereséssel
-• Osszon meg epizódokat és csatornákat továbbfejlesztett közösségi média és e-mail lehetőségekkel, a gPodder.net szolgáltatásokkal és OPML exportálás segítségével
-
-<b>Vezérelje a rendszert</b>
-• Vegye át az irányítást az automatikus letöltés felett: válasszon csatornákat, mellőzze a mobilhálózatokat, válasszon specifikus WiFi-hálózatokat, követelje meg a telefon töltését és adjon meg időpontokat vagy időszakokat
-• Kezelje a tárhelyet a tárolandó epizódok számának megadásával, az okos törléssel és az előnyben részesített hely megadásával
-• Alkalmazkodjon a környezethez a világos és sötét téma használatával
-• Mentse el a feliratkozásait a gPodder.net integrációval és az OPML exporttal
-
-<b>Csatlakozzon az AntennaPod közösséghez!</b>
-Az AntennaPodot aktívan fejlesztik az önkéntesek. Ön is közreműködhet: kóddal vagy megjegyzésekkel!
-
-A barátságos fórumtagjaink örömmel segítenek minden felmerülő kérdésben. Meghívjuk, hogy beszélgessen a funkciókról, valamint általánosságban a podcastolásról.
-https://forum.antennapod.org/
-
-A Transifexen segíthet a fordításokban:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/hu-HU/short-description.txt b/app/src/main/play/listings/hu-HU/short-description.txt
deleted file mode 100644
index 0e9612141..000000000
--- a/app/src/main/play/listings/hu-HU/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Könnyen használható, rugalmas és nyílt forráskódú podcastkezelő és -lejátszó \ No newline at end of file
diff --git a/app/src/main/play/listings/hu-HU/title.txt b/app/src/main/play/listings/hu-HU/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/hu-HU/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/it-IT/full-description.txt b/app/src/main/play/listings/it-IT/full-description.txt
deleted file mode 100644
index 5e75f9420..000000000
--- a/app/src/main/play/listings/it-IT/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod è un riproduttore e gestore di podcast che permette l'accesso immediato a milioni di podcast gratuiti e a pagamento, dai podcaster indipendenti alle grandi emittenti come BBC, NPR e CNN. Aggiungi, importa ed esporta i feed in modo semplice tramite il database di iTunes, i file OPML o i semplici indirizzi RSS.
-Scarica, accoda o ascolta in streaming gli episodi e goditeli come preferisci grazie alla velocità di riproduzione modificabile, al supporto ai capitoli e al timer di spegnimento.
-Risparmia fatica, carica della batteria e dati grazie ai potenti controlli automatizzati per il download degli episodi (orari specifici, intervalli di tempo e reti WiFi specifiche) e l'eliminazione degli episodi (gestione dei preferiti e tempi di cancellazione).
-
-Creato da appassionati di podcast, AntennaPod è libero in tutti i sensi: open source, gratuito e senza pubblicità.
-
-<b>Importa, organizza e riproduci</b>
-• Gestisci la riproduzione ovunque: widget nella schermata home, tendina delle notifiche, cuffie e controlli Bluetooth.
-• Aggiungi e importa le sottoscrizioni tramite iTunes e gPodder, o anche tramite file OPML, collegamenti RSS o Atom.
-• Goditi l'ascolto nel modo che preferisci grazie alla velocità di riproduzione modificabile, al supporto ai capitoli, alla memorizzazione dello stato di riproduzione e al timer di spegnimento avanzato (scuoti per riavviare o riduci il volume)
-• Accedi tramite utente e password ai feed e agli episodi riservati
-
-<b>Tieni traccia, condividi & ricerca</b>
-• Tieni traccia dei migliori episodi di sempre segnandoli come preferiti
-• Trova proprio l'episodio che cercavi grazie alla ricerca nella cronologia, nei titoli e nelle note degli episodi
-• Condividi gli episodi e i feed tramite opzioni avanzate di condivisione via social o email, i servizi di gPodder.net o l'esportazione OPML.
-
-<b>Controlla il sistema</b>
-• Gestisci il download automatico: puoi selezionare i feed, escludere le reti mobili, utilizzare reti WiFi specifiche, impostare il download solo quando in carica e scaricare ad orari o intervalli selezionati.
-• Gestisci lo spazio impostando il numero massimo di episodi da tenere, la cancellazione intelligente e il percorso in cui scaricare i file.
-• Adattalo alle tue preferenze grazie ai temi chiaro o scuro.
-• Effettua il backup delle sottoscrizioni grazie all'integrazione con gPodder.net e all'esportazione in OPML.
-
-<b>Partecipa alla community di AntennaPod!</b>
-AntennaPod è sviluppato da volontari. Anche tu puoi contribuire, con il codice o con dei commenti!
-
-I simpatici membri del nostro forum sono felici di rispondere a qualsiasi domanda tu possa avere. Ti invitiamo anche a discutere di funzionalità e podcasting.
-https://forum.antennapod.org/
-
-Transifex è dove puoi contribuire alla traduzione:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/it-IT/graphics/phone-screenshots/00.png b/app/src/main/play/listings/it-IT/graphics/phone-screenshots/00.png
deleted file mode 100644
index a860cc8c7..000000000
--- a/app/src/main/play/listings/it-IT/graphics/phone-screenshots/00.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/it-IT/graphics/phone-screenshots/01.png b/app/src/main/play/listings/it-IT/graphics/phone-screenshots/01.png
deleted file mode 100644
index b28200a86..000000000
--- a/app/src/main/play/listings/it-IT/graphics/phone-screenshots/01.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/it-IT/graphics/phone-screenshots/02.png b/app/src/main/play/listings/it-IT/graphics/phone-screenshots/02.png
deleted file mode 100644
index 5fd46f51f..000000000
--- a/app/src/main/play/listings/it-IT/graphics/phone-screenshots/02.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/it-IT/graphics/phone-screenshots/03.png b/app/src/main/play/listings/it-IT/graphics/phone-screenshots/03.png
deleted file mode 100644
index 1fcaaba69..000000000
--- a/app/src/main/play/listings/it-IT/graphics/phone-screenshots/03.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/it-IT/graphics/phone-screenshots/04.png b/app/src/main/play/listings/it-IT/graphics/phone-screenshots/04.png
deleted file mode 100644
index f77490481..000000000
--- a/app/src/main/play/listings/it-IT/graphics/phone-screenshots/04.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/it-IT/graphics/phone-screenshots/05.png b/app/src/main/play/listings/it-IT/graphics/phone-screenshots/05.png
deleted file mode 100644
index 14259aa8c..000000000
--- a/app/src/main/play/listings/it-IT/graphics/phone-screenshots/05.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/it-IT/short-description.txt b/app/src/main/play/listings/it-IT/short-description.txt
deleted file mode 100644
index a3c6e1c33..000000000
--- a/app/src/main/play/listings/it-IT/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Riproduttore e gestore di podcast facile da usare, flessibile e open source. \ No newline at end of file
diff --git a/app/src/main/play/listings/it-IT/title.txt b/app/src/main/play/listings/it-IT/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/it-IT/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/iw-IL/full-description.txt b/app/src/main/play/listings/iw-IL/full-description.txt
deleted file mode 100644
index 20cc56675..000000000
--- a/app/src/main/play/listings/iw-IL/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-היישומון אנטנה־פּוֹד הוא נגן ומנהל פודקאסטים שמעניק לך גישה ישירה למיליונים של פודקאסטים בחינם ובתשלום, החל ממגישי פודקאסטים עצמאיים ועד למפיצים גדולים כגון BBC,‏ NPR ו־CNN. ניתן להוסיף, לייבא ולייצא את ההזנות שלהם בקלות יחסית באמצעות מסד נתוני הפודקאסטים של iTunes, קובצי OPML או כתובות של RSS.
-ניתן להוריד, להזרים או לסדר רשימות של פרקים וליהנות מהם בכל דרך שמתאימה לך עם מהירויות נגינה משתנות, תמיכה במקטעים ומתזמן שינה
-ניתן לחסוך במאמץ, סוללה וניצולת חבילת נתונים עם בקרת אוטומציה מתקדמת להורדת פרקים (תוך הגדרת זמנים, מרווחים ורשתות אלחוטיות) ומחיקת פרקים (על בסיס המועדפים והגדרות ההשהיה שלך).
-
-היישומון אנטנהפּוֹד, שנוצר על ידי חובבי פודקאסטים, הוא חופשי במלוא מובן המילה: קוד פתוח, ללא עלות, ללא פרסומות.
-
-<b>ייבוא, ארגון והשמעה</b>
-• ניתן לנהל את הנגינה מכל מקום: וידג׳ט על מסך הבית, התרעות המערכת ופקדי שקע אוזניות ובלוטות׳
-• ניתן להוסיף ולייבא הזנות דרך הספריות של iTunes ושל gPodder.net, קובצי OPML וקישורי RSS או Atom
-• פשוט ליהנות בדרך שלך עם מהירות נגינה משתנה, תמיכה במקטעים, שמירת מיקום הנגינה ומתזמן שינה מתקדם (ניתן לנער כדי לאפס, להנמיך את עצמת השמע)
-• גישה להזנות ולפרקים המוגנים בססמה
-
-<b>מעקב, שיתוף והערכה</b>
-• מעקב אחר הטובים שבטובים על ידי סימון פרקים כמועדפים
-• ניתן לאתר פרק אחד דרך היסטוריית הנגינה או על ידי חיפוש כותרות והערות פרק
-• ניתן לשתף פרקים והזנות דרך אפשרויות מתקדמות ברשתות חברתיות ודוא״ל, שירותי gPodder.net ודרך ייצוא OPML
-
-<b>שליטה במערכת</b>
-• ניתן לשלוט על הורדה אוטומטית: לבחור הזנות, להחריג רשתות סלולריות, לבחור רשתות אלחוטיות מסוימות, לדרוש מהטלפון להיות בטעינה ולהגדיר מועדים או מרווחי זמן
-• ניתן לנהל את האחסון על ידי הגדרת כמות הפרקים שנשמרים במטמון, מחיקה חכמה (בהתבסס על המועדפים ומצב הנגינה שלך) ובחירת המיקום המועדף עליך
-• התאמה לסביבה שלך באמצעות ערכות עיצוב בהירה וכהה
-• גיבוי המינויים שלך עם שילוב מול gPodder.net וייצוא של OPML
-
-<b>מזמינים אותך להצטרף עוד היום לקהילת אנטנהפּוֹד!</b>
-את תהליכי הפיתוח הפעילים של אנטנה־פּוֹד מובילים מתנדבים. ניתן לתרום גם כן, עם קוד או עם הערה!
-
-חברי הפורום החביבים שלנו שמחים לסייע בכל שאלה שעשויה לצוץ לך. מזמינים אותך לדון בתכונות של היישומון ועל פודקאסטים בכלל.
-https://forum.antennapod.org/
-
-Transifex הוא המקום לסייע עם התרגומים:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/iw-IL/short-description.txt b/app/src/main/play/listings/iw-IL/short-description.txt
deleted file mode 100644
index 34ffefafc..000000000
--- a/app/src/main/play/listings/iw-IL/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-מנהל פודקאסטים ונגן קל לשימוש, גמיש ובקוד פתוח \ No newline at end of file
diff --git a/app/src/main/play/listings/iw-IL/title.txt b/app/src/main/play/listings/iw-IL/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/iw-IL/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/ja-JP/full-description.txt b/app/src/main/play/listings/ja-JP/full-description.txt
deleted file mode 100644
index a35cda995..000000000
--- a/app/src/main/play/listings/ja-JP/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod は、独立したポッドキャスターから BBC、NPR、CNN などの大規模な出版社まで、数百万の無料および有料のポッドキャストに即座にアクセスできるポッドキャストマネージャーおよびプレーヤーです。 iTunes ポッドキャストデータベース、OPML ファイル、または単純な RSS URL を使用して、フィードを簡単に追加、インポート、エクスポートできます。
-エピソードをダウンロード、ストリーミング、またはキューに入れて、調整可能な再生速度、チャプターサポート、スリープタイマーで、お好きな方法でお楽しみください。
-エピソードのダウンロード (時間、間隔、WiFi ネットワークの指定) とエピソードの削除 (お気に入りと遅延設定に基づく) の強力な自動化コントロールにより、労力、バッテリー消費量、モバイルデータ通信使用量を節約できます。
-
-ポッドキャスト愛好家によって作られた AntennaPod は、オープンソース、無料、広告なしなど、あらゆる意味でフリーです。
-
-<b>インポート、整理、再生</b>
-• どこからでも再生を管理: ホーム画面のウィジェット、システム通知、イヤホン、Bluetooth コントロール
-• iTunes および gPodder.net ディレクトリー、OPMLファイル、RSS または Atom リンク経由でフィードを追加およびインポートします
-• 調整可能な再生速度、チャプターサポート、記憶した再生位置、高度なスリープタイマー (シェイクしてリセット、音量を下げる) でお好みの方法でお楽しみください
-• パスワードで保護されたフィードとエピソードのアクセス
-
-<b>追跡、共有、感謝</b>
-• エピソードをお気に入りとしてマークすることにより、ベストを追跡します
-• 再生履歴から、またはタイトルとショーノートを検索して、エピソードを見つけます
-• 高度なソーシャルメディア、メールオプション、gPodder.net サービス、OPML エクスポートを介してエピソードとフィードを共有します
-
-<b>システムをコントロール</b>
-• 自動ダウンロードの制御: フィードの選択、モバイル通信ネットワークの除外、特定の WiFi ネットワークの選択、充電時以外のダウンロードやダウンロードの時間や間隔の設定
-• キャッシュされるエピソードの量を設定、スマート削除、お好みの場所を選択してストレージを管理します
-• ライトとダークのテーマを使用して環境に適応します
-• gPodder.net 統合と OPML エクスポートを使用して購読をバックアップします
-
-<b>AntennaPod コミュニティに参加しましょう!</b>
-AntennaPod はボランティアによって活発に開発中です。コードやコメントで、あなたも貢献することができます!
-
-フレンドリーなフォーラムメンバーが、あらゆる質問に喜んでお答えします。機能やポッドキャスト全般についてもご相談ください。
-https://forum.antennapod.org/
-
-Transifex は翻訳を支援する場所です:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/ja-JP/short-description.txt b/app/src/main/play/listings/ja-JP/short-description.txt
deleted file mode 100644
index 71072e758..000000000
--- a/app/src/main/play/listings/ja-JP/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-使いやすくて柔軟な、オープンソース ポッドキャスト マネージャー/プレーヤー \ No newline at end of file
diff --git a/app/src/main/play/listings/ja-JP/title.txt b/app/src/main/play/listings/ja-JP/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/ja-JP/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/ko-KR/full-description.txt b/app/src/main/play/listings/ko-KR/full-description.txt
deleted file mode 100644
index 62a7a54f0..000000000
--- a/app/src/main/play/listings/ko-KR/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-안테나팟은 팟캐스트 관리 및 플레이어 앱으로, 이 앱을 이용해 수백만의 무료 및 유료 팟캐스트에 즉시 접근할 수 있습니다. 팟캐스트는 독립 팟캐스트부터 BBC, NPR, CNN과 같은 대형 퍼블리셔도 있습니다. iTunes 팟캐스트 데이터베이스, OPML 파일, 또는 간단히 RSS URL을 이용해 이들 팟캐스트 피드를 추가하고, 가져오고, 내보낼 수 있습니다.
-에피소드를 다운로드하거나, 스트리밍하거나, 대기열에 쌓아놓고 원하는대로 즐기십시오. 재생 속도를 조절하거나, 챕터 지원 기능, 취침 타이머를 사용할 수 있습니다.
-에피소드 다운로드 (다운로드 시간, 간격, WiFi 네트워크 지정 가능) 및 에피소드 삭제에 (즐겨 찾기 및 지연 시간 설정에 따라) 대해 강력한 자동 컨트롤로 여러분의 수고를 줄이고, 배터리, 휴대폰 데이터 사용을 절약합니다.
-
-팟캐스트 팬이 개발한 안테나팟은 모든 면에서 자유롭습니다: 오픈소스이고, 별도 비용이 없고, 광고가 없습니다.
-
-<b>가져오기, 정리, 재생</b>
-• 어디서든 재생을 관리합니다: 홈스크린 위젯, 시스템 알림, 이어폰 및 블루투스 조작
-• iTunes, gPodder.net 디렉토리, OPML 파일, RSS 또는 Atom 링크에서 피드를 추가하고 가져옵니다.
-• 자기만의 방식으로 청취할 수 있습니다. 재생 속도 조절, 챕터 기능, 저장된 재생 위치, 고급 취침 타이머 (흔들어서 초기화, 작은 볼륨)
-• 비밀번호로 보호된 피드 및 에피소드에 접근
-
-<b>기록, 공유 및 감사 표시</b>
-• 에피소드를 즐겨찾기 표시해 최고의 에피소드를 기록합니다
-• 재생 기록에서 에피소드를 찾거나 제목과 쇼노트를 검색해 찾습니다
-• 발전된 SNS, 이메일, gPodder.net 서비스 또는 OPML 내보내기 옵션을 통해 에피소드와 피드를 공유할 수 있습니다.
-
-<b>시스템 조작</b>
-• 자동 다운로드 동작을 원하는대로 조정하세요: 피드 선택, 모바일 네트워크 제외, 특정 WiFi 네트워크 선택, 충전 필요, 다운로드 시간 및 간격 설정
-• 저장 공간을 관리하세요: 임시 저장할 에피소드 수 설정, 똑똑한 삭제, 원하는 저장 위치 선택
-• 환경에 따라 밝은 테마 또는 어두운 테마 사용
-• gPodder.net 통합 기능 및 OPML 내보내기를 이용해 구독 내역 백업
-
-<b>안테나팟 커뮤니티에 참여하세요!</b>
-안테나팟은 자원자들에 의해 활발하게 개발되고 있습니다. 여러분도 코드 또는 코멘트로 기여할 수 있습니다!
-
-저희의 친절한 포럼 멤버들은 여러분의 어떤 질문에 대해서든 기쁘게 도움을 드릴 것입니다. 기능이나 팟캐스트 일반에 대한 토론도 할 수 있습니다.
-https://forum.antennapod.org/
-
-Transifex는 번역에 도움을 줄 수 있는 곳입니다:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/ko-KR/short-description.txt b/app/src/main/play/listings/ko-KR/short-description.txt
deleted file mode 100644
index fed4feb26..000000000
--- a/app/src/main/play/listings/ko-KR/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-사용하기 쉽고 유연한 오픈소스 팟캐스트 관리 및 플레이어 앱 \ No newline at end of file
diff --git a/app/src/main/play/listings/ko-KR/title.txt b/app/src/main/play/listings/ko-KR/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/ko-KR/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/lt/full-description.txt b/app/src/main/play/listings/lt/full-description.txt
deleted file mode 100644
index 161322aa2..000000000
--- a/app/src/main/play/listings/lt/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-„AntennaPod“ yra tinklalaidžių tvarkytuvė ir leistuvė, įgalinanti prieigą prie milijonų nemokamų ir mokamų tinklalaidžių, nuo nepriklausomų kūrėjų iki didžiųjų leidyklų, tokių kaip „BBC“, „NPR“ ir „CNN“. Be vargo pridėkite, importuokite ir eksportuokite sklaidos kanalus naudodamiesi „iTunes“ tinklalaidžių duomenų baze, OPML failais ar RSS kanalais.
-Atsisiųskite, klausykitės iš karto ar dėkite epizodus į eilę ir mėgaukitės jais pasirinkę atkūrimo spartą, naudodamiesi skyrių palaikymu bei miego laikmačiu.
-Sutaupykite pastangų, baterijos energijos ir suvartotų mobiliųjų duomenų naudodamiesi galingais automatizacijos valdikliais epizodų atsiuntimui (nurodykite laiką, intervalą ir „WiFi“ tinklus) ir epizodų trynimui (remiantis Jūsų mėgstamaisiais ir atidėjimo nustatymais).
-
-Sukurtas tinklalaidžių entuziastų, „AntennaPod“ yra laisvas visomis prasmėmis: atvirojo kodo, be mokesčių, be reklamų.
-
-<b>Importuokite, tvarkykite ir atkurkite</b>
-• Valdykite atkūrimą bet kur: pradžios ekrane, programų pranešimuose, ausinių ar „Bluetooth“ valdikliu
-• Pridėkite ar importuokite sklaidos kanalus iš „iTunes“ ir „gPodder.net“, OPML failų, RSS ar Atom nuorodų
-• Mėgaukitės klausydamiesi taip, kaip Jums patinka, naudodamiesi derinama atkūrimo sparta, skyrių palaikymu, išsaugota atkūrimo pozicija ir miego laikmačiu (pakračius nustatomas iš naujo, mažinamas garsis)
-• Pasiekite slaptažodžiu apsaugotus sklaidos kanalus ir epizodus
-
-<b>Sekite, dalinkitės ir branginkite</b>
-• Kaupkite geriausius žymėdami epizodus kaip mėgstamus
-• Raskite norimą epizodą pasinaudoję atkūrimo istorija ar paieška pavadinimuose ir laidų užrašuose
-• Dalinkitės epizodais ir sklaidos kanalais per socialinius tinklus, el. paštu, „gPodder.net“ ir OPML failus
-
-<b>Valdykite sistemą</b>
-• Valdykite automatinį atsiuntimą: pasirinkite sklaidos kanalus, neleiskite atsiuntimų mobiliuoju ryšiu, apibrėžkite leistinus belaidžius tinklus, reikalaukite, jog atsiuntimai būtų vykdomi įkrovos metu, nurodykite atsiuntimų dienos metą ar intervalą
-• Valdykite laikmenos naudojimą nurodant podėlyje laikomų epizodų kiekį, išmanų trynimą ir nurodant norimą saugojimo vietą
-• Pritaikykite savo aplinkai pasirinkę šviesią ar tamsią temą
-• Kurkite prenumeratų atsargines kopijas „gPodder.net“ ar OPML failais
-
-<b>Prisijunkite prie AntennaPod bendruomenės!</b>
-„AntennaPod“ vysto savanoriai. Ir Jūs galite prisidėti, nuo atsiliepimų iki programinio kodo!
-
-Draugiški mūsų forumo nariai pasiruošę padėti visais turimais klausimais. Kviečiame diskutuoti apie programėlės funkcijas bei bendrai apie tinklalaides.
-https://forum.antennapod.org/
-
-Prie vertimų galite prisidėti „Transifex“:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/lt/short-description.txt b/app/src/main/play/listings/lt/short-description.txt
deleted file mode 100644
index 0a0752647..000000000
--- a/app/src/main/play/listings/lt/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Patogi naudoti, lanksti atvirojo kodo tinklalaidžių tvarkytuvė bei leistuvė \ No newline at end of file
diff --git a/app/src/main/play/listings/lt/title.txt b/app/src/main/play/listings/lt/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/lt/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/nl-NL/full-description.txt b/app/src/main/play/listings/nl-NL/full-description.txt
deleted file mode 100644
index 3de2554e7..000000000
--- a/app/src/main/play/listings/nl-NL/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-Met AntennaPod speel en beheer je alle podcasts en krijg je directe toegang tot duizenden gratis en betaalde podcasts - van onafhankelijke makers tot grote merken zoals BBC, CNN en NPO. Via de iTunes-database, OPML-bestanden en simpele RSS-linkjes voeg je deze podcasts makkelijk toe.
-Download, stream of voeg afleveringen toe aan de wachtrij. Met instelbare afspeelsnelheden, hoofdstukondersteuning en een slaaptimer luister je podcasts op de manier die jij prettig vindt.
-Spaar moeite, je batterij en je databundel met slimme automatische controle op het downloaden van nieuwe afleveringen. En AntennaPod verwijdert ook je oude afleveringen, afhankelijk van je instellingen.
-
-AntennaPod is gemaakt door podcast-enthousiastelingen. Het team van vrijwilligers bieden het gratis aan - vrij van advertenties en open source.
-
-<b>Importeren, organiseren en afspelen</b>
-• Beheer het afspelen op elke manier: met een homescreen widget, in je Android meldingen en via de knoppen op je koptelefoon en bluetooth-apparaat
-• Voeg podcasts toe via iTunes- en gPodder.net-databases, OPML-bestanden en RSS- of Atom-links
-• Bepaal zelf hoe je luistert met aanpasbare afspeelsnelheden, ondersteuning van hoofdstukken, opslag van afspeelpositie voor elke aflevering en een handige 'slaap timer' (schudden om te resetten, volume langzaam zachter)
-• Toegang tot wachtwoord-beveiligde podcasts en afleveringen
-
-<b>Hou bij, deel en waardeer</b>
-• Hou het beste van het beste bij door afleveringen als favoriet te markeren
-• Vindt die ene aflevering terug via de afspeelgeschiedenis of door te zoeken in titels en shownotes
-• Deel podcasts en afleveringen via uitgebreide opties voor sociale media, email, gPodder.net of een OPML-bestand
-
-<b>Hou de controle</b>
-• Beheer automatische downloads: kies je podcasts, sluit mobiele netwerken uit, selecteer specifieke WiFi-verbindingen, vereis dat de telefoon wordt opgeladen en bepaal tijden of intervals
-• Controleer geheugengebruik: stel een maximumaantal gedownloade afleveringen in, laat afleveringen automatisch verwijderen en selecteer zelf je opslaglocatie
-• Voel je een kameleon: kies voor een licht of donker uiterlijk
-• Back-up je abonnementen via gPodder.net en geëxporteerde OPML-bestanden
-
-<b>Doe mee met de AntennaPod-gemeenschap!</b>
-AntennaPod wordt regelmatig geüpdatet door vrijwilligers. En jij kan ook helpen, met code of commentaar!
-
-De vriendelijke leden van ons forum helpen je graag met welke vraag dan ook. Deel gerust ook ideëen voor nieuwe functies of podcasts in het algemeen.
-https://forum.antennapod.org/
-
-Transifex is de beste plek om te helpen met vertalen:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/00.png b/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/00.png
deleted file mode 100644
index df59503e6..000000000
--- a/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/00.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/01.png b/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/01.png
deleted file mode 100644
index c9a93bb17..000000000
--- a/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/01.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/02.png b/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/02.png
deleted file mode 100644
index ac6f2d65d..000000000
--- a/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/02.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/03.png b/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/03.png
deleted file mode 100644
index 464efedc4..000000000
--- a/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/03.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/04.png b/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/04.png
deleted file mode 100644
index 4db1bdfa5..000000000
--- a/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/04.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/05.png b/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/05.png
deleted file mode 100644
index 95cee64e3..000000000
--- a/app/src/main/play/listings/nl-NL/graphics/phone-screenshots/05.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/play/listings/nl-NL/short-description.txt b/app/src/main/play/listings/nl-NL/short-description.txt
deleted file mode 100644
index 31c66d634..000000000
--- a/app/src/main/play/listings/nl-NL/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Gemakkelijk te gebruiken, flexibele en open-source podcastbeheerder en -speler \ No newline at end of file
diff --git a/app/src/main/play/listings/nl-NL/title.txt b/app/src/main/play/listings/nl-NL/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/nl-NL/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/pl-PL/full-description.txt b/app/src/main/play/listings/pl-PL/full-description.txt
deleted file mode 100644
index efa98abd1..000000000
--- a/app/src/main/play/listings/pl-PL/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod to menedżer i odtwarzacz podcastów, który pozwala na natychmiastowy dostęp do milionów darmowych i płatnych podcastów, od niezależnych twórców po wielkie wydawnictwa takie jak BBC, NPR i CNN. Bezproblemowo dodawaj, importuj i eksportuj ich kanały używając bazy danych podcastów iTunes, plików OPML lub zwykłych adresów RSS.
-Pobieraj, streamuj lub dodawaj do kolejki odcinki i korzystaj z nich jak chcesz, przy pomocy konfigurowalnej prędkości odtwarzania, wsparcia rozdziałów i wyłącznika czasowego.
-Oszczędź czas, baterię i ilość pobranych danych komórkowych dzięki wielu możliwościom automatyzacji pobierania odcinków (określanie czasu, interwałów i sieci WiFi) i kasowania odcinków (na podstawie twoich ulubionych i ustawień opóźnienia)
-
-Stworzony przez miłośników podcastów, AntennaPod jest darmowy w każdym znaczeniu tego słowa: otwarty kod, bez opłat, bez reklam.
-
-<b>Importuj, organizuj i odtwarzaj</b>
-• Zarządzaj odtwarzaniem z dowolnego miejsca: widgetu na ekranie głównym, powiadomienia systemowego, pilota na kablu słuchawkowym, urządzeń bluetooth
-Dodawaj i importuj kanały z iTunes i gPodder.net, plików OPML oraz z adresów RSS lub Atom
-• Ciesz się słuchaniem podcastów po swojemu, dzięki konfigurowalnej prędkości odtwarzania, obsłudze rozdziałów, zapamiętywanej pozycji odtwarzania i zaawansowanemu wyłącznikowi czasowemu (potrząśnij aby zresetować, zmniejszanie głośności)
-• Wsparcie dla kanałów i odcinków zabezpieczonych hasłem
-
-<b>Śledź i dziel się</b>
-• Zachowaj najlepsze z najlepszych oznaczając odcinki jako ulubione
-• Odnajdź ten jedyny odcinek dzięki historii odtwarzania lub przez wyszukiwanie po tytułach i opisach
-• Udostępniaj odcinki i kanały dzięki zaawansowanym opcjom mediów społecznościowych i email, usłudze gPodder.net oraz eksporcie OPML
-
- <b>Kontroluj</b>
-• Kontroluj automatyczne pobieranie: wybierz kanały, oszczędzaj dane komórkowe, wybierz określone sieci WiFi, pobieraj tylko podczas ładowania, ustaw czas dnia lub częstotliwość
-• Kontroluj użycie pamięci poprzez ustawienie ilości zachowywanych odcinków, inteligentne kasowanie oraz wybranie domyślnej lokalizacji
-• Dostosuj wygląd dzięki motywom: ciemny, jasny, czarny (dla ekranów AMOLED)
-• Twórz kopie zapasowe swoich subskrypcji dzięki integracji gPodder.net lub eksportuj je do pliku OPML
-
-<b>Dołącz do społeczności AntennaPod</b>
-AntennaPod jest ciągle rozwijane przez ochotników. Ty też możesz pomóc, kodem lub komentarzem!
-
-Życzliwi użytkownicy forum chętnie odpowiedzą na twoje pytania. Zapraszamy do rozmów o funkcjach programu i generalnie o podcastingu.
-https://forum.antennapod.org/
-
-Chcesz pomóc tłumaczyć AntennaPod - możesz to zrobić na Transifex:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/pl-PL/short-description.txt b/app/src/main/play/listings/pl-PL/short-description.txt
deleted file mode 100644
index bb0c603f9..000000000
--- a/app/src/main/play/listings/pl-PL/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Łatwy w użyciu, konfigurowalny otwartoźródłowy menedżer i odtwarzacz podcastów \ No newline at end of file
diff --git a/app/src/main/play/listings/pl-PL/title.txt b/app/src/main/play/listings/pl-PL/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/pl-PL/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/pt-BR/full-description.txt b/app/src/main/play/listings/pt-BR/full-description.txt
deleted file mode 100644
index 2c852b464..000000000
--- a/app/src/main/play/listings/pt-BR/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod é um tocador e gerenciador de podcasts que lhe oferece acesso a milhões de podcasts gratuitos ou pagos, de podcasters independentes ou dos principais publicadores de conteúdo como BBC, NPR e CNN. Adicione, importe e exporte seus feeds facilmente usando a biblioteca do iTunes, arquivos OPML ou URLs RSS.
-Baixe, transmita ou enfileire episódios e curta-os como quiser com velocidades de reprodução ajustáveis, suporte a capítulos e um temporizador.
-Economize esforço, bateria e uso de dados móveis com avançados recursos para automatizar o download de episódios (especificar horários, intervalos e redes WiFi) e a sua remoção (com base em seus favoritos e configurações de atraso).
-
-Feito por entusiastas de podcast, o AntennaPod é gratuito em todos os sentidos da palavra: código aberto, sem custos, sem anúncios.
-
-Importe, organize e toque
-&#8226; Gerencie suas reproduções de qualquer lugar: widget da tela inicial, notificações de sistema e fone de ouvido e controles bluetooth<br>
-&#8226; Adicione and importe feeds pelo iTunes e diretorios gPodder.net, arquivos OPML e links RSS ou Atom<br>
-&#8226; Ouça do seu jeito com velocidade de reprodução ajustável, suporte a capítulos (MP3, VorbisComment e Podlove), marcador da posição de reprodução e um despertador avançado (chacoalhe para reiniciar, volume reduzido e reprodução desacelerada)<br>
-&#8226; Acesse feeds e episódios protegidos por senha
-
-Acompanhe, compartilhe e aprecie
-&#8226; Guarde o melhor do melhor marcando episódios como favoritos<br>
-&#8226; Encontre aquele episódio específico através do histórico de execução ou pelo sistema de busca (através de títulos e anotações)<br>
-&#8226; Compartilhe episódios e <i>feeds</i> através de opções em redes sociais, email, os serviços da gPodder.net e exportação OPML<br>
-
-Controle o sistema
-&#8226; Tenha controle sobre a automação dos <i>downloads</i>: escolha <i>feeds</i>, exclua redes móveis, selecione redes específicas de WiFi, exija que o telefone esteja sendo carregado e defina horários ou intervalos<br>
-&#8226; Gerencie o armazenamento configurando a quantidade de episódios em cache, exclusão inteligente dos episódios (baseada nos seus favoritos e status de reprodução)<br>
-&#8226; Adapte-se ao ambiente utilizando os temas claro ou escuro<br>
-&#8226; Faça <i>backup</i> das suas inscrições com a integração ao gPodder.net e exportação de OPML
-
-Junte-se à comunidade do AntennaPod!
-O AntennaPod está sob constante desenvolvimento através de voluntários. Você também pode contribuir, com código ou um comentário!
-
-Nossos simpáticos membros do fórum ficarão felizes em ajudar com todas as perguntas que você tiver. Você está convidado a discutir sobre funcionalidades e podcasts em geral também.
-https://forum.antennapod.org/
-
-Transifex é o lugar para ajudar com as traduções:<br>
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/pt-BR/short-description.txt b/app/src/main/play/listings/pt-BR/short-description.txt
deleted file mode 100644
index 8f3301cc3..000000000
--- a/app/src/main/play/listings/pt-BR/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Um player de podcasts fácil de usar, flexível e de código aberto \ No newline at end of file
diff --git a/app/src/main/play/listings/pt-BR/title.txt b/app/src/main/play/listings/pt-BR/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/pt-BR/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/pt-PT/full-description.txt b/app/src/main/play/listings/pt-PT/full-description.txt
deleted file mode 100644
index 6774d87f8..000000000
--- a/app/src/main/play/listings/pt-PT/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod é um gestor de podcasts que lhe permite aceder a milhões de podcasts, gratuitos ou pagos, sejam eles publicadores independentes ou grandes cadeias tais como as estações BBC, NPR e CNN. A adição de fontes é muito fácil através do serviço iTunes, ficheiros OPML e fontes RSS.
-Pode descarregar, emitir ou colocar episódios na fila de reprodução ao seu gosto, pode utilizar velocidades variáveis de reprodução, tem suporte a capítulos e um temporizador.
-Poupe tempo, economize bateria e dados móveis através dos mecanismos de controlo de descargas de episódios (possibilidade de especificar intervalos ou horas para as descargas e redes Wi-Fi) e de eliminação de episódios (de acordo com as suas preferências).
-
-Criado por entusiastas de podcasts, AntennaPod é livre em todos os sentidos da palavra: open source, gratuito e sem publicidade.
-
-<b>Importação, organização e reprodução</b>
-• Gestão de podcasts através do widget, barra de notificações e controlos de auriculares ou bluetooth
-• Adicione e importe fontes existentes nos diretórios iTunes e gPodder.net, ficheiros OPML e ligações ATOM e RSS
-• Velocidade variável de reprodução, suporte a capítulos, memorização da posição de reprodução e um temporizador avançado (agite para repor, baixar e aumentar o volume)
-• Acesso a fontes e episódios protegidos por palavra-passe
-
-<b>Monitorizar, partilhar e apreciar</b>
-• Monitorize os seus episódio preferidos marcando-os como favoritos
-• Localize um episódio no histórico de reprodução ou através de uma pesquisa por título ou notas
-• Partilhe episódios e fontes nas redes sociais, por e-mail, no diretório gPodder.net ou através de ficheiros OPML
-
-<b>Controlo de sistema</b>
-• Controle todas as descargas automáticas: escolha as fontes, exclua redes móveis, especifique as redes Wi-Fi, indique se o telefone deve estar a ser carregado e defina as horas ou intervalos das descargas
-• Gestão do armazenamento através da cache de episódios, da eliminação inteligente e selecionando a localização dos dados
-• Adapte-se ao seu ambiente através dos temas claro ou escuro
-• Guarde as suas subscrições com a integração gPodder.net ou através da exportação OPML
-
-<b>Integrar a comunidade AntennaPod!</b>
-O AntennaPod é desenvolvido por voluntários. Você também pode contribuir na programação ou reportando os erros encontrados!
-
-Os membros do nosso fórum podem ajudar-vos em relação às vossas dúvidas. Sinta-se à vontade para propor funcionalidades ou simplesmente falar connosco.
-https://forum.antennapod.org/
-
-Transifex é o local certo para ajudar a traduzir a aplicação:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/pt-PT/short-description.txt b/app/src/main/play/listings/pt-PT/short-description.txt
deleted file mode 100644
index c558abaca..000000000
--- a/app/src/main/play/listings/pt-PT/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Gestor e reprodutor de podcasts simples, flexível e open souce \ No newline at end of file
diff --git a/app/src/main/play/listings/pt-PT/title.txt b/app/src/main/play/listings/pt-PT/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/pt-PT/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/ro/full-description.txt b/app/src/main/play/listings/ro/full-description.txt
deleted file mode 100644
index f806d7565..000000000
--- a/app/src/main/play/listings/ro/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AantennaPod este un manager și player de podcasturi care îți oferă acces instant la milioane de podcasturi gratuite și plătite, provenite fie de la creatori independeți, fie de la sutudiouri deja consacrate precum BBC, NPR și CNN. Adaugă, importă și exportă fluxurile lor de date fără probleme folosind baza de date iTunes, fișiere OPML și simple linkuri RSS.
-Descarcă, redă în flux sau pune în coada de redare și bucură-te în modul în care îți place ție, cu posibilitatea de a adjusta viteza de playback, suport pentru capitole și existența unui cronometru pentru somn.
-Economisiți efort, baterie și date mobile prin folosirea controalelor automatizate pentru descărcarea episoadelor (se pote specifica timpul și rețele WiFi) și ștergerea episoadelor (în baza setărilor tale favorite și setările de întârziere).
-
-Făcut de entiziaști pentru podcasturi, AntennaPod este gratuit în toate sensurile cuvântului: open-source, fără costuri, fără reclame.
-
-<b>Importă, organizează și redă</b>
-Gestionați redarea de oriunde: widgetul de pe ecranul principal, notificările de sistem, controlul de pe căști și controlul bluetooth
-Adaugă și importă fluxuri de date folosind iTunes și directoare gPodder.net, fișiere OPML și RSS sau linkuri de tip Atom
-Bucură-te de auduție cu viteza de redare adjustabilă, suport penru capitole, poziția de redare ce este memorată și un cronometru pentru somn avansat (scutură pentru a reseta, volum mai mic)
-Accesează fluxuri de date și episoade ce sunt protejate de o parolă
-
-<b>Urmărește, partajați și apreciați</b>
-Urmărește-i pe cei mai buni dintre cei mai buni prin adăugarea acestor podcasturi la favorite
-Găsește "podcastul acela" prin căutarea în istoricul de redare sau prin căutarea în titlurile sau descrierile podcasturilor
-Partajează episoade și fluxuri de date prin oțiuni avansate pentru social media și opțiuni pentru email, prin serviciile gPodder.net și prin exportul în fișier OPML
-
-<b>Controlează sistemul</b>
-Preia controlul asupra descărcărilor automate: alege fluxuri de date, exclude rețele mobile, selectează anumite rețele WiFi, impune necesitatea telefonului de a fi încărcat și setează intervale de timp
-Gestionează stocarea prin setarea numărului de episoade memorate, ștergere inteligentă și selecție a locației preferate
-Adapteazăte la propriul mediu prin folosirea unei teme întunecate sau luminoase
-Creează o copie de siguranță cu integrarea gPodder.net și exportul în fișiere OPML
-
-<b>Alătură-te comunității AntennaPod!</b>
-AntennaPod se dezvoltă activ cu ajutorul voluntarilor. Poți să contribui și tu cu cod sau cu un comentariu!
-
-Membrii forumului nostru sunt prietenoși si fericiți să vă ajute cu fiecare întrebare ai avea. Ești invitat să discuți funcționalități noi sau podcasturi în general.
-https://forum.antennapod.org/
-
-Pentru a ajuta cu traducerile atunci trebuie să folosești Transifex
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/ro/short-description.txt b/app/src/main/play/listings/ro/short-description.txt
deleted file mode 100644
index 7bae371d9..000000000
--- a/app/src/main/play/listings/ro/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Manager și player de podcasturi ușor de utilizat, flexibil și open-source \ No newline at end of file
diff --git a/app/src/main/play/listings/ro/title.txt b/app/src/main/play/listings/ro/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/ro/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/ru-RU/full-description.txt b/app/src/main/play/listings/ru-RU/full-description.txt
deleted file mode 100644
index a3f86ff91..000000000
--- a/app/src/main/play/listings/ru-RU/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod — менеджер и проигрыватель подкастов, который обеспечит вас мгновенным доступом к миллионам бесплатных и платных подкастов, как от независимых подкастеров, так и крупных издательских домов. С легкостью добавляйте, импортируйте и экспортируйте их каналы используя каталог подкастов iTunes, файлы OPML или адреса каналов RSS.
-Загружайте, транслируйте по сети или добавляйте выпуски в очередь и наслаждайтесь ими так, как вам нравится, с регулируемой скоростью воспроизведения, поддержкой оглавления и таймером сна.
-Экономьте время, заряд батареи и мобильный трафик при помощи мощных средств автоматизации загрузки выпусков (фильтрация, указание времени и интервалов, а также сетей WiFi) и их удаления (избранные и настройки хранения).
-
-Созданное поклонниками подкастов, AntennaPod — бесплатное и свободное приложение без рекламы и платежей.
-
-<b>Импортируйте, систематизируйте и слушайте</b>
-• Управляйте любым способом: виджетом, системным уведомлением или кнопками проводных и беспроводных гарнитур
-• Добавление и импорт каналов через каталоги iTunes и gPodder.net, файлы OPML и ссылки на каналы в RSS или Atom
-• Приятное вам прослушивание с регулировкой скорости воспроизведения, оглавлениями, запоминанием места воспроизведения и продвинутым таймером сна (со сбросом при встряхивании, снижением громкости)
-• Доступ к каналам и выпускам, защищенным паролем
-
-<b>Отслеживайте, делитесь и благодарите</b>
-• Отслеживайте лучших из лучших, помещая выпуски в избранное
-• Поиск того самого выпуска в истории воспроизведения или по заголовкам и примечаниям
-• Разнообразие способов поделиться выпусками и каналами через социальные сети и e-mail, услуги gPodder.net и экспорт в OPML
-
-<b>Управляйте системой</b>
-• Управление автоматической загрузкой: выбор отдельных каналов, запрет на использование мобильных сетей, выбор определенных точек доступа WiFi, только во время зарядки телефона и в заданное время или интервалы
-• Управление хранением: ограничение количества кешируемых выпусков, автоудаление и выбор расположения файлов
-• Приспосабливается к вашему окружению посредством светлого или темного оформления
-• Резервирование ваших подписок путем интеграции с gPodder.net и экпорта в OPML
-
-<b>Присоединяйтесь к сообществу AntennaPod!</b>
-AntennaPod постоянно развивается силами добровольцев. Вы тоже можете сделать свой вклад при помощи кода или комментария!
-
-Участники нашего дружелюбного форума рады помочь вам с любым вопросом. Мы приглашаем вас обсудить возможности приложения и подкастинг в целом.
-https://forum.antennapod.org/
-
-Помогайте с переводом приложения на Transifex:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/ru-RU/short-description.txt b/app/src/main/play/listings/ru-RU/short-description.txt
deleted file mode 100644
index 44d1be699..000000000
--- a/app/src/main/play/listings/ru-RU/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Удобное и гибкое приложение с открытым исходным кодом для подкастов \ No newline at end of file
diff --git a/app/src/main/play/listings/ru-RU/title.txt b/app/src/main/play/listings/ru-RU/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/ru-RU/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/sk/full-description.txt b/app/src/main/play/listings/sk/full-description.txt
deleted file mode 100644
index c929fa327..000000000
--- a/app/src/main/play/listings/sk/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod je správca a prehrávač podcastov, ktorý vám sprostredkuje okamžitý prístup k miliónom bezplatným a spoplatneným podcastom - od nezávislých podcastérov až k vydavateľstvám ako BBC, NPR a CNN. Pridávajte, importujte a exportujte ich zdroje bez problémov pomocou databázy podcastov iTunes, OPML súborov alebo odkazov na RSS.
-Stiahnite, streamujte alebo plánujte epizódy a užívajte si ich ako sa vám páči s nastaviteľnou rýchlosťou prehrávania, podporou kapitol a časovačom vypnutia.
-Ušetrite si námahu, baterku a mobilné dáta pomocou výkonnej automatickej kontroly sťahovania epizód (určite čas, intervaly a WiFi siete) a mazania epizód (založené na obľúbených epizódach a nastavení oneskorenia).
-
-AntennaPod je spravovaný podcastovými entuziastami a je slobodný v každom slova zmysle: otvorený zdrojový kód, zadarmo, bez reklamy.
-
-<b>Importovať, spravovať a prehrať</b>
-• Ovládajte prehrávanie odkiaľkoľvek: domovská obrazovka, systémové upozornenia a handsfree a ovládanie cez bluetooth
-• Pridať a importovať zdroje pomocou priečinkov iTunes a gPodder.net, OPML súborov a odkazov RSS alebo Atom
-• Užívajte si počúvanie s nastaviteľnou rýchlosťou prehrávania, podporou kapitol, zapamätanou pozíciou prehrávania a pokročilým nastavením vypnutia (zatrasením resetuj, stíš hlasitosť)
-Počúvajte heslom chránené zdroje a epizódy
-
-<b>Sledovať, zdielať a oceniť</b>
-• Sledujte najlepšie z najlepších pomocou označenia ako obľúbené
-• Nájdite epizódu v histórií prehrávaní alebo v nadpisoch a popisoch
-• Zdielajte epizódy a zdroje pomocou pokročilých nastavení sociálnych sietí a e-mailu, služieb gPodder.net a cez export do OPML súboru
-
-<b>Spravovať systém</b>
-• Spravujte automatické sťahovanie: vyberte zdroje, vylúčte mobilné siete, vyberte konkrétne WiFi siete, vyžadujte nabíjanie telefónu a nastavte časy a intervaly
-• Spravujte úložisko nastavením počtu uložených epizód, inteligentným mazaním a zvolením umiestnenia súborov
-• Prispôsobte si vzhľad na svetlý alebo tmavý
-• Zálohujte si odbery pomocou gPodder.net a OPML exportu
-
-<b>Pridať sa do komunity AntennaPod!</b>
-AntennaPod aktívne vyvíjajú dobrovoľníci. Tiež môžete prispieť kódom alebo komentárom.
-
-Na našom fóre môžete v priateľskej atmosfére diskutovať a nájsť odpovede na vaše otázky o nových funkciách alebo všeobecne o podcastingu.
-https://forum.antennapod.org/
-
-Transifex je miesto, kde môžete pomôcť s prekladom:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/sk/short-description.txt b/app/src/main/play/listings/sk/short-description.txt
deleted file mode 100644
index d0162e6f9..000000000
--- a/app/src/main/play/listings/sk/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Ľahko použíteľný, flexibilný a open source správca a prehrávač podcastov \ No newline at end of file
diff --git a/app/src/main/play/listings/sk/title.txt b/app/src/main/play/listings/sk/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/sk/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/sl/full-description.txt b/app/src/main/play/listings/sl/full-description.txt
deleted file mode 100644
index 097779bf9..000000000
--- a/app/src/main/play/listings/sl/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod je upravljalnik in predvajalnik podkastov, ki vam omogoča takojšen dostop do milijonov brezplačnih in plačljivih podkastov, od neodvisnih podkastov do velikih založb, kot so BBC, NPR in CNN. Brez težav dodajte, uvozite in izvozite njihove vire z bazo podatkov podkastov iTunes, datotekami OPML ali preprostimi URL-ji RSS.
-Prenesite, pretočite ali postavite v čakalno vrsto epizode in uživajte v njih, kot želite, z nastavljivimi hitrostmi predvajanja, podporo za poglavja in časovnikom za spanje.
-Prihranite trud, baterijo in porabo mobilnih podatkov z zmogljivimi avtomatskimi kontrolami za prenos epizod (določite čas, intervale in omrežja WiFi) in brisanje epizod (na podlagi vaših priljubljenih in nastavitev zakasnitve).
-
-AntennaPod, ki so ga izdelali ljubitelji podkastov, je brezplačen v vseh pomenih besede: odprtokoden, brez stroškov, brez oglasov.
-
-<b>Uvozi, preuredi in predvajaj</b>
-• Upravljajte predvajanje od koder koli: pripomoček za začetni zaslon, sistemsko obvestilo ter kontrolniki za ušesne čepke in bluetooth
-• Dodajanje in uvoz virov prek imenikov iTunes in gPodder.net, datotek OPML in povezav RSS ali Atom
-• Uživajte v poslušanju z nastavljivo hitrostjo predvajanja, podporo za poglavja, shranjenim položajem predvajanja in naprednim časovnikom za izklop (tresenje za ponastavitev, nižja glasnost)
-• Dostopajte do virov in epizod, zaščitenih z geslom
-
-<b>Spremljajte, delite in cenite</b>
-• Spremljajte najboljše od najboljših tako, da epizode označite kot priljubljene
-• To epizodo poiščite v zgodovini predvajanja ali z iskanjem po naslovih in oddajah
-• Delite epizode in vire prek naprednih možnosti družbenih medijev, e-pošte, storitev gPodder.net in preko izvoza OPML
-
-<b>Nadzorujte sistem</b>
-• Prevzemite nadzor nad samodejnim prenosom: izberite vire, izključite mobilna omrežja, izberite določena omrežja WiFi, zahtevajte, da se telefon polni in nastavite čase ali intervale
-• Upravljajte shranjevanje tako, da nastavite količino predpomnjenih epizod, pametno brisanje in izberete želeno lokacijo
-• Prilagodite se svojemu okolju s pomočjo svetle in temne teme
-• Varnostno kopirajte svoje naročnine z integracijo gPodder.net in izvozom OPML
-
-<b>Pridružite se skupnosti AntennaPod</b>
-AntennaPod aktivno razvijajo prostovoljci. Prispevate lahko tudi vi, s kodo ali s komentarjem!
-
-Naši prijazni člani foruma Vam z veseljem pomagajo pri vsakem vprašanju. Vabljeni tudi k razpravi o funkcijah in podcastingu na splošno.
-https://forum.antennapod.org/
-
-Transifex je kraj za pomoč pri prevodih:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/sl/short-description.txt b/app/src/main/play/listings/sl/short-description.txt
deleted file mode 100644
index 7ed232575..000000000
--- a/app/src/main/play/listings/sl/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Enostaven odprtokodni, prilagodljivi podkast predvajalnik \ No newline at end of file
diff --git a/app/src/main/play/listings/sl/title.txt b/app/src/main/play/listings/sl/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/sl/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/sv-SE/full-description.txt b/app/src/main/play/listings/sv-SE/full-description.txt
deleted file mode 100644
index d52e26390..000000000
--- a/app/src/main/play/listings/sv-SE/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-Antennapod är en podcasthanterare och spelare som ger dig omedelbar tillgång till millioner av gratis och betalda podcasts, allt ifrån oberoende podcasters till publiceringsjättar som BBC, NPR och CNN. Lägg till, importera och exportera enkelt deras flöden med hjälp av Itunes-podcastdatabas, OPML filer eller enkla RSS URL:er.
-Ladda ner, strömma eller köa episoder och avnjut dem på det sätt du gillar med justerbar uppspelningshastighet, kapitelstöd och insomningstimer.
-Spara tid, batteri och mobildata med kraftfulla automatiseringskontroller för nedladdning av episoder (specifera tider, intervall och Wi-Fi nätverk) och borttagning av episoder (baserat på dina favoriseringar och fördröjningsinställningar).
-
-Gjord av podcastentusiaster, AntennaPod är fri i ordets alla bemärkelser: öppen källkod, inga kostnader, ingen reklam.
-
-<b>Importera, organisera och spela</b>
-• Hantera uppspelningen från vartsomhelst: hemskärmswidget, aviseringsfältet och hörlurs/bluetoth-kontroller
-• Lägg till och importera flöden via iTunes och gPodder.net, OPML filer och RSS eller Atom länkar
-• Njut av att lyssna på ditt sätt med justerbar uppspelningshastighet, kapitelstöd (MP3, VorbisComment och Podlove), ihågkommen uppspelningsposition och en avancerad insomningstimer (skaka för återställning, sänk volymen)
-• Kom åt lösenordsskyddade flöden och episoder
-
-<b>Håll reda på, dela & uppskatta</b>
-• Håll ordning på de bästa av de bästa med favoritmarkering av episoder
-• Hitta just den där episoden i uppspelningshistoriken eller genom sökning i titel och avsnittsanteckningar
-• Dela episoder och flöden med avancerade vald för social media och och email, tjänsten gPodder.net och via OPML export
-
-<b>Behärska systemet</b>
-• Ta kontroll över automatisk nedladdning: välj flöden, exkludera mobilnätverk, välj specifika Wi-Fi nätverk, kräv att telefonen är inkopplad för laddning och sätt tider eller intervall för körning
-• Hantera lagring med inställningar för antalet episoder i cachen, smart borttagning (med hänsyn till dina favoriter och uppspelningsstatus) och välj din föredragna plats
-• Anpassa till din omgivning med det ljusa och mörka temat
-• Säkerhetskopiera dina prenumerationer genom att integrera gPodder.net och OPML exportering
-
-<b>Gå med i AntennaPods gemenskap!</b>
-AntennaPod utvecklas av frivilliga eldsjälar. Även du kan bidra via utvecklingsinsatser eller kommentarer!
-
-Våra vänliga forummedlemmar hjälper glatt till med alla frågor du har. Du inbjuds också att diskutera funktioner och podcasting generellt.
-https://forum.antennapod.org/
-
-Transifex är platsen att gå till för att hjälpa till med översättningen:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/sv-SE/short-description.txt b/app/src/main/play/listings/sv-SE/short-description.txt
deleted file mode 100644
index 2273fc5e4..000000000
--- a/app/src/main/play/listings/sv-SE/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Användarvänlig och flexibel podcasthanterare och spelare med öppen källkod \ No newline at end of file
diff --git a/app/src/main/play/listings/sv-SE/title.txt b/app/src/main/play/listings/sv-SE/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/sv-SE/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/uk/full-description.txt b/app/src/main/play/listings/uk/full-description.txt
deleted file mode 100644
index f084bceaf..000000000
--- a/app/src/main/play/listings/uk/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod — це менеджер та плеєр подкастів, який забезпечить Вам доступ до мільйонів безкоштовних та комерційних подкастів. Додавайте, імпортуйте та експортуйте канали за допомогою бази подкастів iTunes, файлів OPML або просто посилань на RSS.
-Завантажуйте, слухайте або додавайте епізоди до черги так, як вам подобається: з налаштуванням швидкості програвання, підтримкою глав та таймером сну.
-Економте зусилля, енергію акумулятора та використання мобільних даних. Автоматизуйте завантаження епізодів (вкажіть час, інтервали та мережі Wi-Fi) та їх видалення.
-
-Створене прихильниками подкастів, AntennaPod — безкоштовна і вільна програма без реклами.
-
-<b>Імпортуйте, систематизуйте та слухайте</b>
-• Керуйте програванням будь-де: з віджета, системного сповіщення, кнопками дротових і бездротових гарнітур
-• Додавайте та імпортуйте канали з каталогів iTunes та gPodder.net, файлів OPML та посилань на RSS або Atom
-Слухайте так, як вам подобається, з налаштуванням швидкості відтворення, підтримкою глав, зберіганням позиції відтворення та таймером сну (потрясіть, щоб зменшити гучність, перезапустити)
-• Доступ до каналів та епізодів, які захищені паролем
-
-<b>Слідкуйте, діліться та цінуйте</b>
- • Зберігайте найкраще в улюблених епізодах
-• Відшукайте той самий епізод в історії програвання або за допомогою пошуку
-• Діліться епізодами та каналами за допомогою соцмереж та електронної пошти, сервісів gPodder.net та через експорт OPML файлів
-
-<b>Керуйте системою</b>
-• Керуйте автоматичним завантаженням: вибирайте канали, мобільні мережі, мережі Wi-Fi, завантажуйте тільки під час зарядки або у встановлений час і інтервали
-• Керуйте пам’яттю, встановлюйте ліміт на кеш епізодів, налагоджуйте розумне видалення та вибирайте місце зберігання
-• Адаптуйте для себе, використовуючи світлу та темну тему
-• Зберігайте підписки за допомогою інтеграції з gPodder.net та експорту OPML
-
-<b>Долучайтесь до спільноти AntennaPod!</b>
-AntennaPod швидко розвивається волонтерами. Ви теж можете допомогти: кодом або зауваженнями!
-
-Наші дружні учасники форуму із задоволенням допоможуть з кожним Вашим запитанням. Запрошуємо вас обговорити функції та подкастинг загалом.
-https://forum.antennapod.org/
-
-Допоможіть з перекладом на Transifex:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/uk/short-description.txt b/app/src/main/play/listings/uk/short-description.txt
deleted file mode 100644
index afd654442..000000000
--- a/app/src/main/play/listings/uk/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Легкий у використанні, плеєр і менеджер подкастів з відкритим кодом \ No newline at end of file
diff --git a/app/src/main/play/listings/uk/title.txt b/app/src/main/play/listings/uk/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/uk/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/zh-CN/full-description.txt b/app/src/main/play/listings/zh-CN/full-description.txt
deleted file mode 100644
index ec6368eb6..000000000
--- a/app/src/main/play/listings/zh-CN/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod是一个播客管理器和播放器,可以让你即时访问数以百万计的免费和付费播客,从独立播主到大型新闻机构出版社,如 BBC、NPR 和 CNN。使用 iTunes podcast 数据库、OPML 文件或简单的 RSS 地址轻而易举地添加、导入和导出它们的提要(Feed)。
-下载,在线播放或对音频进行排队,并借助可调节的回放速度、章节支持及睡眠定时器以您喜爱的方式享用它们。
-通过针对音频下载(指定时间、间隔和 WiFi 网络)和音频删除(根据您的喜好和延迟设置)的强大自动控制功能,节省精力、电池电量和移动数据使用量。
-
-由播客爱好者制作的 AntennaPod 在任何意义上都是免费的:开源、免费、无广告。
-
-<b>导入、组织和播放</b>
-•从任何地方管理播放:主屏幕小部件、系统通知、耳塞和蓝牙控制
-•通过 iTunes 和 gPodder.net 目录、OPML 文件和 RSS 或 Atom 链接添加和导入提要
-•通过可调整的回放速度、章节支持、记忆回放位置及高级睡眠定时器(晃动手机重置、调低音量)以您的方式享受收听
-•访问有密码保护的提要和音频
-
-<b>保持跟踪、分享和欣赏</b>
-•标记你最爱的播客剧集,并随时保持更新
-•通过回放历史或通过搜索标题和 shownote 找到某期节目
-•通过高级社交媒体和电子邮件选项、gPodder.net 服务和导出 OPML 分享剧集和提要
-
-<b>控制系统</b>
-•控制自动下载:选择订阅源、排除移动网络、选择特定的WiFi网络、要求手机充电,设置次数或间隔
-•通过设置缓存的剧集数量、智能删除和选择您的首选位置来管理存储
-•使用浅色和深色主题适应你的环境
-• 使用 gPodder.net 集成和 OPML 导出备份订阅
-
-<b>加入 AntennaPod 社区</b>
-AntennaPod 用爱发电,借助社区持续更新。您也可以通过提交代码或发表评论做出贡献!
-
-我们友好的论坛成员乐意为您的每个问题提供帮助。我们还邀请您讨论功能和播客。
-https://forum.antennapod.org/
-
-您可以前往 Transifex 协助翻译:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/zh-CN/short-description.txt b/app/src/main/play/listings/zh-CN/short-description.txt
deleted file mode 100644
index e6072fcf3..000000000
--- a/app/src/main/play/listings/zh-CN/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-易用、灵活的开源播客管理工具与播放器 \ No newline at end of file
diff --git a/app/src/main/play/listings/zh-CN/title.txt b/app/src/main/play/listings/zh-CN/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/zh-CN/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/listings/zh-TW/full-description.txt b/app/src/main/play/listings/zh-TW/full-description.txt
deleted file mode 100644
index 97144018e..000000000
--- a/app/src/main/play/listings/zh-TW/full-description.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-AntennaPod 是 Podcast 訂閱管理工具。從百家爭鳴的獨立 Postcasters 到各立山頭的大廠如 BBC、CNN、NPR 等,讓數百萬免費或付費的 Podcast 唾手可得。您可以使用 iTunes 的 Podcast 資料庫、OPML 檔或RSS 網址等方式,輕鬆新增、匯入或匯出資料來源。
-將各 Podcast 劇集下載、串流播放或放入隊列,然後可以調整播放速度、跳躍章節、設定睡眠時間等等,用您喜愛的方式聆聽享受。
-用強大的自動下載設定指定時間、頻率、WiFi 下載,並且可以依據最愛劇集與延遲設定等方式刪除已經聽過的劇集。省力、省電、省數據。
-
-AntennaPod 由 Podcast 愛好者鼎力製作,免費、無廣告、開放原始碼,給您最全面的自由。
-
-<b>匯入、管理、播放</b>
-• 從主畫面小工具、系統通知、耳機或藍牙控制器隨處播放
-• 利用 iTunes、gPodder.net 目錄、OPML 檔、RSS 或 Atom 連結匯入、新增 Podcast
-• 擁有自訂播放速度、支援章節、記憶播放進度、設定睡眠時間等功能,享受自由聆聽的樂趣
-• 支援以密碼保護的 Podcast
-
-<b>保留、分享</b>
-• 將特定一集設定為最愛,永久留存
-• 自播放紀錄、標題或附註等處搜尋特定一集
-• 以社群網站、電子郵件、gPodder.net 或匯出 OPML 等方式分享 Podcast
-
-<b>一手掌控</b>
-• 選擇特定 Podcast、只用特定 WiFi 下載、僅在充電時下載、設定更新頻率與次數等等機制,完整控制自動下載功能
-• 設定暫存集數上限、智慧刪除、設定儲存位置等機制,方便管理設備空間
-• 根據系統環境採用明亮或暗夜佈景
-• 以整合的 gPodder.net 服務或匯出 OPML 來備份訂閱清單
-
-<b>加入 AntennaPod 社群!</b>
-AntennaPod 由志工熱情製作,您也可以加入 -- 幫忙寫程式或給意見都非常歡迎!
-
-若您遇上使用問題,論壇上的社群成員都樂意提供協助。您也可以加入討論未來功能、其他 Podcast 相關的事情。
-https://forum.antennapod.org/
-
-協助翻譯請至 Transifex:
-https://www.transifex.com/antennapod/antennapod \ No newline at end of file
diff --git a/app/src/main/play/listings/zh-TW/short-description.txt b/app/src/main/play/listings/zh-TW/short-description.txt
deleted file mode 100644
index 2606389d1..000000000
--- a/app/src/main/play/listings/zh-TW/short-description.txt
+++ /dev/null
@@ -1 +0,0 @@
-易用、靈活的開源 podcast 管理及播放器 \ No newline at end of file
diff --git a/app/src/main/play/listings/zh-TW/title.txt b/app/src/main/play/listings/zh-TW/title.txt
deleted file mode 100644
index 31552f353..000000000
--- a/app/src/main/play/listings/zh-TW/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-AntennaPod \ No newline at end of file
diff --git a/app/src/main/play/release-notes/en-US/default.txt b/app/src/main/play/release-notes/en-US/default.txt
deleted file mode 100644
index e95521704..000000000
--- a/app/src/main/play/release-notes/en-US/default.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-∙ Show currently playing episode and honor sort in episode list view in Android Auto (@tonytamsf)
-∙ Add 'next chapter' button to playback notification and Android Auto interface (@matejdro)
-∙ New sort dialog (@ByteHamster)
-∙ Move 'skip silence' checkbox to playback speed dialog (@quails4Eva)
-∙ Add 'reset' button to episodes and subscriptions filters (@ueen)
-∙ Always show 'share' button on player toolbar (@ueen)
-∙ Bugfix to show remaining time in queue in hours instead of days (@ByteHamster) \ No newline at end of file
diff --git a/app/src/main/res/layout/authentication_dialog.xml b/app/src/main/res/layout/authentication_dialog.xml
index f311fc1dd..0d54420d4 100644
--- a/app/src/main/res/layout/authentication_dialog.xml
+++ b/app/src/main/res/layout/authentication_dialog.xml
@@ -1,59 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:padding="16dp">
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="16dp">
<com.google.android.material.textfield.TextInputLayout
- style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="8dp">
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="8dp"
+ style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
- android:id="@+id/usernameEditText"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="@string/username_label"
- android:lines="1"/>
+ android:id="@+id/usernameEditText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/username_label"
+ android:lines="1" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
<com.google.android.material.textfield.TextInputLayout
- style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1">
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
- android:id="@+id/passwordEditText"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="@string/password_label"
- android:inputType="textPassword"
- android:lines="1"/>
+ android:id="@+id/passwordEditText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/password_label"
+ android:inputType="textPassword"
+ android:lines="1" />
</com.google.android.material.textfield.TextInputLayout>
- <com.joanzapata.iconify.widget.IconTextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/showPasswordButton"
- android:text="{fa-eye}"
- android:padding="8dp"
- android:textColor="?android:attr/textColorPrimary"
- android:background="?attr/selectableItemBackgroundBorderless"
- android:alpha="0.6"
- android:textSize="20sp"
- android:layout_marginLeft="8dp"
- android:layout_marginStart="8dp"/>
+ <ImageView
+ android:id="@+id/showPasswordButton"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:src="@drawable/ic_eye"
+ android:layout_gravity="center_vertical"
+ android:padding="8dp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:alpha="0.6"
+ android:textSize="20sp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp" />
</LinearLayout>
-</LinearLayout> \ No newline at end of file
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/dialog_switch_preference.xml b/app/src/main/res/layout/dialog_switch_preference.xml
index 87f321c86..45fe21a90 100644
--- a/app/src/main/res/layout/dialog_switch_preference.xml
+++ b/app/src/main/res/layout/dialog_switch_preference.xml
@@ -6,7 +6,7 @@
android:layout_height="match_parent"
android:padding="24dp">
- <androidx.appcompat.widget.SwitchCompat
+ <com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/dialogSwitch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/downloadlog_item.xml b/app/src/main/res/layout/downloadlog_item.xml
index 9ca19b531..2609f1134 100644
--- a/app/src/main/res/layout/downloadlog_item.xml
+++ b/app/src/main/res/layout/downloadlog_item.xml
@@ -28,13 +28,12 @@
android:orientation="horizontal"
android:gravity="center_vertical">
- <com.joanzapata.iconify.widget.IconTextView
- android:id="@+id/txtvIcon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="16dp"
+ android:layout_height="16dp"
+ android:importantForAccessibility="no"
android:layout_marginEnd="4dp"
- android:padding="2dp"
- android:textSize="18sp"
android:gravity="center" />
<TextView
diff --git a/app/src/main/res/layout/edit_tags_dialog.xml b/app/src/main/res/layout/edit_tags_dialog.xml
index b20facbf0..f4096e939 100644
--- a/app/src/main/res/layout/edit_tags_dialog.xml
+++ b/app/src/main/res/layout/edit_tags_dialog.xml
@@ -13,7 +13,7 @@
android:layout_height="wrap_content"
android:text="@string/feed_folders_include_root" />
- <com.joanzapata.iconify.widget.IconTextView
+ <TextView
android:id="@+id/commonTagsInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/feeditemlist_header.xml b/app/src/main/res/layout/feeditemlist_header.xml
index 45f8e8ff8..9b6d190a8 100644
--- a/app/src/main/res/layout/feeditemlist_header.xml
+++ b/app/src/main/res/layout/feeditemlist_header.xml
@@ -140,7 +140,7 @@
</RelativeLayout>
- <com.joanzapata.iconify.widget.IconTextView
+ <TextView
android:id="@+id/txtvFailure"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/playback_speed_feed_setting_dialog.xml b/app/src/main/res/layout/playback_speed_feed_setting_dialog.xml
index 48d69e4a9..50eb4f84f 100644
--- a/app/src/main/res/layout/playback_speed_feed_setting_dialog.xml
+++ b/app/src/main/res/layout/playback_speed_feed_setting_dialog.xml
@@ -34,4 +34,10 @@
</LinearLayout>
+ <CheckBox
+ android:id="@+id/skipSilenceFeed"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/pref_skip_silence_title" />
+
</LinearLayout>
diff --git a/app/src/main/res/layout/proxy_settings.xml b/app/src/main/res/layout/proxy_settings.xml
index e4e57cc92..3467291eb 100644
--- a/app/src/main/res/layout/proxy_settings.xml
+++ b/app/src/main/res/layout/proxy_settings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="wrap_content"
android:layout_width="match_parent"
+ android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
@@ -79,12 +79,12 @@
android:hint="@string/optional_hint"
android:inputType="textPassword" />
- <com.joanzapata.iconify.widget.IconTextView
+ <TextView
android:id="@+id/txtvMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:visibility="invisible"
- android:gravity="center"/>
+ android:gravity="center" />
</LinearLayout>
diff --git a/app/src/main/res/layout/swipeactions_dialog.xml b/app/src/main/res/layout/swipeactions_dialog.xml
index a1f0b7ae6..637c376d5 100644
--- a/app/src/main/res/layout/swipeactions_dialog.xml
+++ b/app/src/main/res/layout/swipeactions_dialog.xml
@@ -6,7 +6,7 @@
android:orientation="vertical"
android:padding="16dp">
- <androidx.appcompat.widget.SwitchCompat
+ <com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/enableSwitch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/app/src/play/java/de/danoeh/antennapod/dialog/RatingDialog.java b/app/src/play/java/de/danoeh/antennapod/dialog/RatingDialog.java
index 23b74b07e..c38ae2659 100644
--- a/app/src/play/java/de/danoeh/antennapod/dialog/RatingDialog.java
+++ b/app/src/play/java/de/danoeh/antennapod/dialog/RatingDialog.java
@@ -11,10 +11,10 @@ import android.util.Log;
import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;
+import com.google.android.gms.tasks.Task;
import com.google.android.play.core.review.ReviewInfo;
import com.google.android.play.core.review.ReviewManager;
import com.google.android.play.core.review.ReviewManagerFactory;
-import com.google.android.play.core.tasks.Task;
import de.danoeh.antennapod.BuildConfig;
diff --git a/build.gradle b/build.gradle
index 449de8584..dce2b1a10 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,31 +1,21 @@
buildscript {
- repositories {
- google()
- mavenCentral()
- gradlePluginPortal()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:7.4.2'
- classpath "gradle.plugin.com.github.spotbugs.snom:spotbugs-gradle-plugin:4.7.0"
- classpath 'org.codehaus.groovy:groovy-xml:3.0.13'
- }
+ ext.agpVersion = "8.0.2"
}
-
-allprojects {
- repositories {
- google()
- mavenCentral()
- maven { url "https://jitpack.io" }
- }
+plugins {
+ id 'com.android.application' version "$agpVersion" apply false
+ id 'com.android.library' version "$agpVersion" apply false
+ id 'com.github.spotbugs' version '4.8.0' apply false
+ id 'checkstyle'
}
project.ext {
// AndroidX
- annotationVersion = "1.2.0"
- appcompatVersion = "1.3.1"
- coreVersion = "1.5.0"
- fragmentVersion = "1.3.6"
- mediaVersion = "1.4.3"
+ annotationVersion = "1.4.0"
+ appcompatVersion = "1.5.1"
+ coreVersion = "1.8.0"
+ fragmentVersion = "1.5.5"
+ mediaVersion = "1.6.0"
+ media3Version = "1.1.1"
paletteVersion = "1.0.0"
preferenceVersion = "1.1.1"
recyclerViewVersion = "1.2.1"
@@ -38,17 +28,10 @@ project.ext {
commonsioVersion = "2.5"
jsoupVersion = "1.15.1"
glideVersion = "4.13.2"
- okhttpVersion = "3.12.10"
- okioVersion = "1.17.5"
+ okhttpVersion = "4.12.0"
eventbusVersion = "3.3.1"
rxAndroidVersion = "2.1.1"
rxJavaVersion = "2.2.2"
- iconifyVersion = "2.2.2"
- annimonStreamVersion = "1.2.2"
- exoPlayerVersion = "2.14.2"
-
- // Google Play build
- wearableSupportVersion = "2.6.0"
//Tests
awaitilityVersion = "3.1.6"
@@ -60,14 +43,17 @@ project.ext {
testCoreVersion = "1.5.0"
}
-apply plugin: "checkstyle"
checkstyle {
toolVersion '10.3.1'
}
-task checkstyle(type: Checkstyle) {
+tasks.register('checkstyle', Checkstyle) {
+ minHeapSize = "200m"
+ maxHeapSize = "2g"
classpath = files()
source "${project.rootDir}"
+ exclude("**/generated-sources/**")
exclude("**/gen/**")
+ exclude("**/build/**")
exclude("**/generated/**")
}
diff --git a/common.gradle b/common.gradle
index 65eed001c..97960149b 100644
--- a/common.gradle
+++ b/common.gradle
@@ -32,8 +32,8 @@ android {
}
compileOptions {
- sourceCompatibility JavaVersion.VERSION_11
- targetCompatibility JavaVersion.VERSION_11
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
}
testOptions {
@@ -56,7 +56,7 @@ android {
}
}
-tasks.withType(Test) {
+tasks.withType(Test).configureEach {
testLogging {
exceptionFormat "full"
events "skipped", "passed", "failed"
@@ -66,39 +66,54 @@ tasks.withType(Test) {
}
gradle.projectsEvaluated {
- tasks.withType(JavaCompile) {
- options.compilerArgs << "-Xlint"
+ tasks.withType(JavaCompile).tap {
+ configureEach {
+ options.compilerArgs << "-Xlint"
+ }
}
}
apply plugin: 'com.github.spotbugs'
spotbugs {
+ toolVersion = '4.2.3'
effort = 'max'
reportLevel = 'medium'
excludeFilter = rootProject.file('config/spotbugs/exclude.xml')
ignoreFailures = true // Handled by printing task
}
-gradle.taskGraph.beforeTask { task ->
- if (task.name.toLowerCase().contains('spotbugs')) {
- task.doLast {
- def reportFile = task.project.file("build/reports/spotbugs/playDebug.xml")
- if (!reportFile.exists()) return
- def slurped = new groovy.xml.XmlSlurper().parse(reportFile)
-
- def foundErrors = false
- slurped['BugInstance'].each { bug ->
- logger.error "[SpotBugs] ${bug['LongMessage']} [${bug.@'type'}]"
- bug['SourceLine'].each { line ->
- logger.error "[SpotBugs] ${line['Message']}"
- foundErrors = true
+gradle.taskGraph.whenReady { taskGraph ->
+ taskGraph.allTasks.each { task ->
+ if (task.name.toLowerCase().contains('spotbugs')) {
+ task.doLast {
+ def reportFile = task.project.file("build/reports/spotbugs/debug.xml")
+ def reportFilePlay = task.project.file("build/reports/spotbugs/playDebug.xml")
+
+ if (reportFile.exists()) {
+ parseSpotBugsXml(task, reportFile)
+ }
+ if (reportFilePlay.exists()) {
+ parseSpotBugsXml(task, reportFilePlay)
}
}
- if (foundErrors) {
- throw new TaskExecutionException(task,
- new Exception("SpotBugs violations were found. See output above for details."))
- }
}
}
}
+
+def parseSpotBugsXml(task, xmlFile) {
+ def slurped = new groovy.xml.XmlSlurper().parse(xmlFile)
+
+ def foundErrors = false
+ slurped['BugInstance'].each { bug ->
+ logger.error "[SpotBugs] ${bug['LongMessage']} [${bug.@'type'}]"
+ bug['SourceLine'].each { line ->
+ logger.error "[SpotBugs] ${line['Message']}"
+ foundErrors = true
+ }
+ }
+ if (foundErrors) {
+ throw new TaskExecutionException(task,
+ new Exception("SpotBugs violations were found. See output above for details."))
+ }
+}
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index 95203de5a..ffd6f6497 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -125,6 +125,14 @@
value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
</module>
<module name="MethodParamPad"/>
+ <module name="Indentation">
+ <property name="basicOffset" value="4"/>
+ <property name="braceAdjustment" value="0"/>
+ <property name="caseIndent" value="4"/>
+ <property name="throwsIndent" value="8"/>
+ <property name="lineWrappingIndentation" value="8"/>
+ <property name="arrayInitIndent" value="4"/>
+ </module>
<module name="NoWhitespaceBefore">
<property name="tokens"
value="COMMA, SEMI, POST_INC, POST_DEC, DOT, ELLIPSIS, METHOD_REF"/>
diff --git a/config/spotbugs/exclude.xml b/config/spotbugs/exclude.xml
index d544e86d9..7469f93e3 100644
--- a/config/spotbugs/exclude.xml
+++ b/config/spotbugs/exclude.xml
@@ -5,18 +5,30 @@
<Class name="de.danoeh.antennapod.adapter.NavListAdapter"/>
</Match>
<Match>
- <Bug pattern="BC_UNCONFIRMED_CAST_OF_RETURN_VALUE"/>
- <Class name="de.danoeh.antennapod.net.ssl.NoV1SslSocketFactory"/>
+ <Bug pattern="DLS_DEAD_LOCAL_STORE"/>
+ <Class name="de.danoeh.antennapod.ui.statistics.StatisticsFragment"/>
</Match>
<Match>
<Bug pattern="DM_DEFAULT_ENCODING"/>
<Class name="de.danoeh.antennapod.parser.media.vorbis.VorbisCommentReader"/>
</Match>
<Match>
+ <Bug pattern="EQ_CHECK_FOR_OPERAND_NOT_COMPATIBLE_WITH_THIS"/>
+ <Class name="de.danoeh.antennapod.model.feed.FeedMedia"/>
+ </Match>
+ <Match>
+ <Bug pattern="EQ_CHECK_FOR_OPERAND_NOT_COMPATIBLE_WITH_THIS"/>
+ <Class name="de.danoeh.antennapod.model.playback.RemoteMedia"/>
+ </Match>
+ <Match>
<Bug pattern="HSC_HUGE_SHARED_STRING_CONSTANT"/>
<Class name="de.danoeh.antennapod.net.ssl.BackportCaCerts"/>
</Match>
<Match>
+ <Bug pattern="ICAST_IDIV_CAST_TO_DOUBLE"/>
+ <Class name="de.danoeh.antennapod.ui.echo.screens.RotatingSquaresScreen"/>
+ </Match>
+ <Match>
<Bug pattern="MS_CANNOT_BE_FINAL"/>
<Class name="de.danoeh.antennapod.core.service.playback.PlaybackService"/>
</Match>
@@ -25,10 +37,6 @@
<Class name="de.danoeh.antennapod.fragment.NavDrawerFragment"/>
</Match>
<Match>
- <Bug pattern="NM_SAME_SIMPLE_NAME_AS_SUPERCLASS"/>
- <Class name="de.danoeh.antennapod.menuhandler.MenuItemUtils"/>
- </Match>
- <Match>
<Bug pattern="NP_NONNULL_PARAM_VIOLATION"/>
<Class name="de.danoeh.antennapod.activity.MainActivity"/>
</Match>
@@ -41,8 +49,8 @@
<Class name="de.danoeh.antennapod.model.feed.FeedMedia"/>
</Match>
<Match>
- <Bug pattern="NP_NULL_PARAM_DEREF"/>
- <Class name="de.danoeh.antennapod.model.feed.FeedMedia"/>
+ <Bug pattern="RV_RETURN_VALUE_IGNORED_BAD_PRACTICE"/>
+ <Class name="de.danoeh.antennapod.core.service.download.DownloadRequestCreator"/>
</Match>
<Match>
<Bug pattern="RV_RETURN_VALUE_IGNORED_BAD_PRACTICE"/>
@@ -50,37 +58,34 @@
</Match>
<Match>
<Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"/>
- <Class name="de.danoeh.antennapod.PodcastApp"/>
- </Match>
- <Match>
- <Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"/>
- <Class name="de.danoeh.antennapod.core.service.download.DownloadService"/>
- </Match>
- <Match>
- <Bug pattern="MS_CANNOT_BE_FINAL"/>
- <Class name="de.danoeh.antennapod.core.service.download.DownloadService"/>
+ <Class name="de.danoeh.antennapod.core.service.playback.PlaybackService"/>
</Match>
<Match>
<Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"/>
- <Class name="de.danoeh.antennapod.core.service.playback.PlaybackService"/>
+ <Class name="de.danoeh.antennapod.ui.home.sections.EpisodesSurpriseSection"/>
</Match>
<Match>
- <Bug pattern="UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD"/>
- <Class name="de.danoeh.antennapod.core.storage.NavDrawerData$TagDrawerItem"/>
+ <Bug pattern="URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD"/>
+ <Class name="de.danoeh.antennapod.playback.base.PlaybackServiceMediaPlayer"/>
</Match>
<Match>
- <Bug pattern="UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD"/>
- <Class name="de.danoeh.antennapod.core.cast.CastButtonVisibilityManager"/>
+ <Bug pattern="URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD"/>
+ <Class name="de.danoeh.antennapod.playback.base.PlaybackServiceMediaPlayer$PSMPInfo"/>
</Match>
<Match><Class name="de.danoeh.antennapod.core.ClientConfig"/></Match>
- <Match><Package name="de.danoeh.antennapod.core.glide"/></Match>
<Match><Package name="de.danoeh.antennapod.databinding"/></Match>
+ <Match><Package name="de.danoeh.antennapod.core.databinding"/></Match>
+ <Match><Package name="de.danoeh.antennapod.ui.common.databinding"/></Match>
+ <Match><Package name="de.danoeh.antennapod.ui.echo.databinding"/></Match>
+ <Match><Package name="de.danoeh.antennapod.ui.statistics.databinding"/></Match>
+ <Match><Bug pattern="DMI_RANDOM_USED_ONLY_ONCE"/></Match>
<Match><Bug pattern="EI_EXPOSE_REP"/></Match>
<Match><Bug pattern="EI_EXPOSE_REP2"/></Match>
<Match><Bug pattern="HE_EQUALS_NO_HASHCODE"/></Match>
+ <Match><Bug pattern="HE_EQUALS_USE_HASHCODE"/></Match>
<Match><Bug pattern="ICAST_INTEGER_MULTIPLY_CAST_TO_LONG"/></Match>
<Match><Bug pattern="IS2_INCONSISTENT_SYNC"/></Match>
<Match><Bug pattern="NP_METHOD_PARAMETER_TIGHTENS_ANNOTATION"/></Match>
@@ -96,6 +101,8 @@
<Match><Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED"/></Match>
<Match><Bug pattern="SF_SWITCH_NO_DEFAULT"/></Match>
<Match><Bug pattern="SIC_INNER_SHOULD_BE_STATIC_ANON"/></Match>
+ <Match><Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"/></Match>
<Match><Bug pattern="UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR"/></Match>
+ <Match><Bug pattern="VA_FORMAT_STRING_USES_NEWLINE"/></Match>
<Match><Bug pattern="WMI_WRONG_MAP_ITERATOR"/></Match>
</FindBugsFilter>
diff --git a/core/build.gradle b/core/build.gradle
index bff9eda59..4385b7cd6 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -35,6 +35,7 @@ dependencies {
implementation project(':playback:base')
implementation project(':playback:cast')
implementation project(':storage:database')
+ implementation project(':storage:importexport')
implementation project(':storage:preferences')
implementation project(':ui:app-start-intent')
implementation project(':ui:common')
@@ -48,6 +49,9 @@ dependencies {
implementation 'androidx.documentfile:documentfile:1.0.1'
implementation "androidx.fragment:fragment:$fragmentVersion"
implementation "androidx.media:media:$mediaVersion"
+ implementation "androidx.media3:media3-datasource-okhttp:$media3Version"
+ implementation "androidx.media3:media3-exoplayer:$media3Version"
+ implementation "androidx.media3:media3-ui:$media3Version"
implementation "androidx.preference:preference:$preferenceVersion"
implementation "androidx.work:work-runtime:$workManagerVersion"
implementation "com.google.android.material:material:$googleMaterialVersion"
@@ -59,25 +63,15 @@ dependencies {
implementation "com.github.bumptech.glide:okhttp3-integration:$glideVersion@aar"
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
implementation "com.squareup.okhttp3:okhttp-urlconnection:$okhttpVersion"
- implementation "com.squareup.okio:okio:$okioVersion"
implementation "org.greenrobot:eventbus:$eventbusVersion"
annotationProcessor "org.greenrobot:eventbus-annotation-processor:$eventbusVersion"
implementation "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
- implementation "com.annimon:stream:$annimonStreamVersion"
-
- implementation "com.google.android.exoplayer:exoplayer-core:$exoPlayerVersion"
- implementation "com.google.android.exoplayer:exoplayer-ui:$exoPlayerVersion"
- implementation "com.google.android.exoplayer:extension-okhttp:$exoPlayerVersion"
-
- // Non-free dependencies:
- playApi "com.google.android.support:wearable:$wearableSupportVersion"
- compileOnly "com.google.android.wearable:wearable:$wearableSupportVersion"
testImplementation "androidx.test:core:$testCoreVersion"
testImplementation "org.awaitility:awaitility:$awaitilityVersion"
testImplementation "junit:junit:$junitVersion"
- testImplementation 'org.mockito:mockito-inline:3.5.13'
+ testImplementation 'org.mockito:mockito-core:5.11.0'
testImplementation "org.robolectric:robolectric:$robolectricVersion"
testImplementation 'javax.inject:javax.inject:1'
androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
diff --git a/core/src/free/java/de/danoeh/antennapod/core/service/playback/WearMediaSession.java b/core/src/free/java/de/danoeh/antennapod/core/service/playback/WearMediaSession.java
deleted file mode 100644
index 5998a1e2f..000000000
--- a/core/src/free/java/de/danoeh/antennapod/core/service/playback/WearMediaSession.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package de.danoeh.antennapod.core.service.playback;
-
-import android.support.v4.media.session.MediaSessionCompat;
-import android.support.v4.media.session.PlaybackStateCompat;
-
-class WearMediaSession {
- /**
- * Take a custom action builder and add no extras, because this is not the Play version of the app.
- */
- static void addWearExtrasToAction(PlaybackStateCompat.CustomAction.Builder actionBuilder) {
- // no-op
- }
-
- static void mediaSessionSetExtraForWear(MediaSessionCompat mediaSession) {
- // no-op
- }
-}
diff --git a/core/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml
index 71cf676a0..99fd3de05 100644
--- a/core/src/main/AndroidManifest.xml
+++ b/core/src/main/AndroidManifest.xml
@@ -20,6 +20,7 @@
android:label="@string/app_name"
android:enabled="true"
android:exported="true"
+ android:foregroundServiceType="mediaPlayback"
tools:ignore="ExportedService">
<intent-filter>
diff --git a/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java b/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java
index 79c6dd6bc..a78ae71a3 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java
@@ -10,6 +10,9 @@ import android.util.Log;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
+import de.danoeh.antennapod.storage.importexport.OpmlElement;
+import de.danoeh.antennapod.storage.importexport.OpmlReader;
+import de.danoeh.antennapod.storage.importexport.OpmlWriter;
import org.apache.commons.io.IOUtils;
import org.xmlpull.v1.XmlPullParserException;
@@ -31,9 +34,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import de.danoeh.antennapod.core.export.opml.OpmlElement;
-import de.danoeh.antennapod.core.export.opml.OpmlReader;
-import de.danoeh.antennapod.core.export.opml.OpmlWriter;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.core.storage.DBReader;
@@ -81,7 +81,7 @@ public class OpmlBackupAgent extends BackupAgentHelper {
try {
// Write OPML
- new OpmlWriter().writeDocument(DBReader.getFeedList(), writer, mContext);
+ OpmlWriter.writeDocument(DBReader.getFeedList(), writer);
// Compare checksum of new and old file to see if we need to perform a backup at all
if (digester != null) {
@@ -90,17 +90,18 @@ public class OpmlBackupAgent extends BackupAgentHelper {
// Get the old checksum
if (oldState != null) {
- FileInputStream inState = new FileInputStream(oldState.getFileDescriptor());
- int len = inState.read();
-
- if (len != -1) {
- byte[] oldChecksum = new byte[len];
- IOUtils.read(inState, oldChecksum, 0, len);
- Log.d(TAG, "Old checksum: " + new BigInteger(1, oldChecksum).toString(16));
-
- if (Arrays.equals(oldChecksum, newChecksum)) {
- Log.d(TAG, "Checksums are the same; won't backup");
- return;
+ try (final FileInputStream inState = new FileInputStream(oldState.getFileDescriptor())) {
+ int len = inState.read();
+
+ if (len != -1) {
+ byte[] oldChecksum = new byte[len];
+ IOUtils.read(inState, oldChecksum, 0, len);
+ Log.d(TAG, "Old checksum: " + new BigInteger(1, oldChecksum).toString(16));
+
+ if (Arrays.equals(oldChecksum, newChecksum)) {
+ Log.d(TAG, "Checksums are the same; won't backup");
+ return;
+ }
}
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/CommonSymbols.java b/core/src/main/java/de/danoeh/antennapod/core/export/CommonSymbols.java
deleted file mode 100644
index 2ce340328..000000000
--- a/core/src/main/java/de/danoeh/antennapod/core/export/CommonSymbols.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package de.danoeh.antennapod.core.export;
-
-public class CommonSymbols {
-
- public static final String HEAD = "head";
- public static final String BODY = "body";
- public static final String TITLE = "title";
-
- public static final String XML_FEATURE_INDENT_OUTPUT = "http://xmlpull.org/v1/doc/features.html#indent-output";
-
-}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/ExportWriter.java b/core/src/main/java/de/danoeh/antennapod/core/export/ExportWriter.java
deleted file mode 100644
index e60609569..000000000
--- a/core/src/main/java/de/danoeh/antennapod/core/export/ExportWriter.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package de.danoeh.antennapod.core.export;
-
-import android.content.Context;
-import java.io.IOException;
-import java.io.Writer;
-import java.util.List;
-
-import de.danoeh.antennapod.model.feed.Feed;
-
-public interface ExportWriter {
-
- void writeDocument(List<Feed> feeds, Writer writer, Context context)
- throws IllegalArgumentException, IllegalStateException, IOException;
-
- String fileExtension();
-
-}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/LocalFeedUpdater.java b/core/src/main/java/de/danoeh/antennapod/core/feed/LocalFeedUpdater.java
index d63fd50f2..0c793d0c5 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/LocalFeedUpdater.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/LocalFeedUpdater.java
@@ -242,8 +242,8 @@ public class LocalFeedUpdater {
}
private static void reportError(Feed feed, String reasonDetailed) {
- DownloadResult status = new DownloadResult(feed, feed.getTitle(),
- DownloadError.ERROR_IO_ERROR, false, reasonDetailed);
+ DownloadResult status = new DownloadResult(feed.getTitle(), feed.getId(),
+ Feed.FEEDFILETYPE_FEED, false, DownloadError.ERROR_IO_ERROR, reasonDetailed);
DBWriter.addDownloadStatus(status);
DBWriter.setFeedLastUpdateFailed(feed.getId(), true);
}
@@ -252,7 +252,8 @@ public class LocalFeedUpdater {
* Reports a successful download status.
*/
private static void reportSuccess(Feed feed) {
- DownloadResult status = new DownloadResult(feed, feed.getTitle(), DownloadError.SUCCESS, true, null);
+ DownloadResult status = new DownloadResult(feed.getTitle(), feed.getId(),
+ Feed.FEEDFILETYPE_FEED, true, DownloadError.SUCCESS, null);
DBWriter.addDownloadStatus(status);
DBWriter.setFeedLastUpdateFailed(feed.getId(), false);
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/util/PlaybackSpeedUtils.java b/core/src/main/java/de/danoeh/antennapod/core/feed/util/PlaybackSpeedUtils.java
index d0824e00b..cd98507ba 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/util/PlaybackSpeedUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/util/PlaybackSpeedUtils.java
@@ -4,6 +4,7 @@ import android.util.Log;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedMedia;
+import de.danoeh.antennapod.model.feed.FeedPreferences;
import de.danoeh.antennapod.model.playback.MediaType;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.storage.preferences.UserPreferences;
@@ -50,4 +51,25 @@ public final class PlaybackSpeedUtils {
return playbackSpeed;
}
+
+ /**
+ * Returns the currently configured skip silence for the specified media.
+ */
+ public static FeedPreferences.SkipSilence getCurrentSkipSilencePreference(Playable media) {
+ FeedPreferences.SkipSilence skipSilence = FeedPreferences.SkipSilence.GLOBAL;
+ if (media != null) {
+ skipSilence = PlaybackPreferences.getCurrentlyPlayingTemporarySkipSilence();
+ if (skipSilence == FeedPreferences.SkipSilence.GLOBAL && media instanceof FeedMedia) {
+ FeedItem item = ((FeedMedia) media).getItem();
+ if (item != null && item.getFeed() != null && item.getFeed().getPreferences() != null) {
+ skipSilence = item.getFeed().getPreferences().getFeedSkipSilence();
+ }
+ }
+ }
+ if (skipSilence == FeedPreferences.SkipSilence.GLOBAL) {
+ skipSilence = UserPreferences.isSkipSilence()
+ ? FeedPreferences.SkipSilence.AGGRESSIVE : FeedPreferences.SkipSilence.OFF;
+ }
+ return skipSilence;
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
index 160b6b774..d6f6cdb43 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
@@ -10,6 +10,7 @@ import android.util.Log;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.event.PlayerStatusEvent;
import de.danoeh.antennapod.model.feed.FeedMedia;
+import de.danoeh.antennapod.model.feed.FeedPreferences;
import de.danoeh.antennapod.model.playback.MediaType;
import de.danoeh.antennapod.model.playback.Playable;
import de.danoeh.antennapod.playback.base.PlayerStatus;
@@ -64,6 +65,12 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference
private static final String PREF_CURRENTLY_PLAYING_TEMPORARY_PLAYBACK_SPEED
= "de.danoeh.antennapod.preferences.temporaryPlaybackSpeed";
+ /**
+ * A temporary skip silence preference which overrides the per-feed skip silence for the currently playing
+ * media. Considered unset if set to null;
+ */
+ private static final String PREF_CURRENTLY_PLAYING_TEMPORARY_SKIP_SILENCE
+ = "de.danoeh.antennapod.preferences.temporarySkipSilence";
/**
* Value of PREF_CURRENTLY_PLAYING_MEDIA if no media is playing.
@@ -123,6 +130,11 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference
return prefs.getFloat(PREF_CURRENTLY_PLAYING_TEMPORARY_PLAYBACK_SPEED, SPEED_USE_GLOBAL);
}
+ public static FeedPreferences.SkipSilence getCurrentlyPlayingTemporarySkipSilence() {
+ return FeedPreferences.SkipSilence.fromCode(prefs.getInt(
+ PREF_CURRENTLY_PLAYING_TEMPORARY_SKIP_SILENCE, FeedPreferences.SkipSilence.GLOBAL.code));
+ }
+
public static void writeNoMediaPlaying() {
SharedPreferences.Editor editor = prefs.edit();
editor.putLong(PREF_CURRENTLY_PLAYING_MEDIA_TYPE, NO_MEDIA_PLAYING);
@@ -170,9 +182,17 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference
editor.apply();
}
- public static void clearCurrentlyPlayingTemporaryPlaybackSpeed() {
+ public static void setCurrentlyPlayingTemporarySkipSilence(boolean skipSilence) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt(PREF_CURRENTLY_PLAYING_TEMPORARY_SKIP_SILENCE, skipSilence
+ ? FeedPreferences.SkipSilence.AGGRESSIVE.code : FeedPreferences.SkipSilence.OFF.code);
+ editor.apply();
+ }
+
+ public static void clearCurrentlyPlayingTemporaryPlaybackSettings() {
SharedPreferences.Editor editor = prefs.edit();
editor.remove(PREF_CURRENTLY_PLAYING_TEMPORARY_PLAYBACK_SPEED);
+ editor.remove(PREF_CURRENTLY_PLAYING_TEMPORARY_SKIP_SILENCE);
editor.apply();
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java b/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java
index 161af58e1..837cb692e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java
@@ -31,7 +31,7 @@ public class MediaButtonReceiver extends BroadcastReceiver {
if (intent == null || intent.getExtras() == null) {
return;
}
- KeyEvent event = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT);
+ KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (event != null && event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
ClientConfigurator.initialize(context);
Intent serviceIntent = new Intent(PLAYBACK_SERVICE_INTENT);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java
index eea4d2082..4f9efdb9c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java
@@ -11,8 +11,6 @@ import androidx.work.ForegroundInfo;
import androidx.work.WorkManager;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
-import com.annimon.stream.Collectors;
-import com.annimon.stream.Stream;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import de.danoeh.antennapod.core.ClientConfigurator;
@@ -104,11 +102,16 @@ public class FeedUpdateWorker extends Worker {
private Notification createNotification(@Nullable List<Feed> toUpdate) {
Context context = getApplicationContext();
String contentText = "";
- String bigText = "";
+ StringBuilder bigText = new StringBuilder();
if (toUpdate != null) {
contentText = context.getResources().getQuantityString(R.plurals.downloads_left,
toUpdate.size(), toUpdate.size());
- bigText = Stream.of(toUpdate).map(feed -> "• " + feed.getTitle()).collect(Collectors.joining("\n"));
+ for (int i = 0; i < toUpdate.size(); i++) {
+ bigText.append("• ").append(toUpdate.get(i).getTitle());
+ if (i != toUpdate.size() - 1) {
+ bigText.append("\n");
+ }
+ }
}
return new NotificationCompat.Builder(context, NotificationUtils.CHANNEL_ID_DOWNLOADING)
.setContentTitle(context.getString(R.string.download_notification_title_feeds))
@@ -142,8 +145,9 @@ public class FeedUpdateWorker extends Worker {
}
} catch (Exception e) {
DBWriter.setFeedLastUpdateFailed(feed.getId(), true);
- DownloadResult status = new DownloadResult(feed, feed.getTitle(),
- DownloadError.ERROR_IO_ERROR, false, e.getMessage());
+ DownloadResult status = new DownloadResult(feed.getTitle(),
+ feed.getId(), Feed.FEEDFILETYPE_FEED, false,
+ DownloadError.ERROR_IO_ERROR, e.getMessage());
DBWriter.addDownloadStatus(status);
}
toUpdate.remove(0);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequestCreator.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequestCreator.java
index fd5babdd1..9ade2f03a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequestCreator.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequestCreator.java
@@ -31,7 +31,7 @@ public class DownloadRequestCreator {
return new DownloadRequest.Builder(dest.toString(), feed)
.withAuthentication(username, password)
- .lastModified(feed.getLastUpdate());
+ .lastModified(feed.getLastModified());
}
public static DownloadRequest.Builder create(FeedMedia media) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpCredentialEncoder.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpCredentialEncoder.java
index c1b63e873..9866f91b6 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpCredentialEncoder.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpCredentialEncoder.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.service.download;
-import okio.ByteString;
+import android.util.Base64;
import java.io.UnsupportedEncodingException;
@@ -9,7 +9,7 @@ public abstract class HttpCredentialEncoder {
try {
String credentials = username + ":" + password;
byte[] bytes = credentials.getBytes(charset);
- String encoded = ByteString.of(bytes).base64();
+ String encoded = Base64.encodeToString(bytes, Base64.NO_WRAP);
return "Basic " + encoded;
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java
index 5da250e15..264740032 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java
@@ -87,12 +87,12 @@ public class FeedParserTask implements Callable<FeedHandlerResult> {
}
if (successful) {
- downloadResult = new DownloadResult(feed, feed.getHumanReadableIdentifier(), DownloadError.SUCCESS,
- successful, reasonDetailed);
+ downloadResult = new DownloadResult(feed.getHumanReadableIdentifier(), feed.getId(),
+ Feed.FEEDFILETYPE_FEED, true, DownloadError.SUCCESS, reasonDetailed);
return result;
} else {
- downloadResult = new DownloadResult(feed, feed.getHumanReadableIdentifier(), reason,
- successful, reasonDetailed);
+ downloadResult = new DownloadResult(feed.getHumanReadableIdentifier(), feed.getId(),
+ Feed.FEEDFILETYPE_FEED, false, reason, reasonDetailed);
return null;
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/MediaDownloadedHandler.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/MediaDownloadedHandler.java
index 019f311d2..98c470f21 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/MediaDownloadedHandler.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/MediaDownloadedHandler.java
@@ -95,8 +95,8 @@ public class MediaDownloadedHandler implements Runnable {
Log.e(TAG, "MediaHandlerThread was interrupted");
} catch (ExecutionException e) {
Log.e(TAG, "ExecutionException in MediaHandlerThread: " + e.getMessage());
- updatedStatus = new DownloadResult(media, media.getEpisodeTitle(),
- DownloadError.ERROR_DB_ACCESS_ERROR, false, e.getMessage());
+ updatedStatus = new DownloadResult(media.getEpisodeTitle(), media.getId(),
+ FeedMedia.FEEDFILETYPE_FEEDMEDIA, false, DownloadError.ERROR_DB_ACCESS_ERROR, e.getMessage());
}
if (item != null) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java
index 1900ed7f2..51adbf477 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java
@@ -6,36 +6,42 @@ import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import android.view.SurfaceHolder;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Consumer;
-import com.google.android.exoplayer2.C;
-import com.google.android.exoplayer2.DefaultLoadControl;
-import com.google.android.exoplayer2.DefaultRenderersFactory;
-import com.google.android.exoplayer2.ExoPlaybackException;
-import com.google.android.exoplayer2.Format;
-import com.google.android.exoplayer2.MediaItem;
-import com.google.android.exoplayer2.PlaybackParameters;
-import com.google.android.exoplayer2.Player;
-import com.google.android.exoplayer2.SeekParameters;
-import com.google.android.exoplayer2.SimpleExoPlayer;
-import com.google.android.exoplayer2.audio.AudioAttributes;
-import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSource;
-import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
-import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor;
-import com.google.android.exoplayer2.source.MediaSource;
-import com.google.android.exoplayer2.source.ProgressiveMediaSource;
-import com.google.android.exoplayer2.source.TrackGroupArray;
-import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
-import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
-import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
-import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
-import com.google.android.exoplayer2.ui.DefaultTrackNameProvider;
-import com.google.android.exoplayer2.ui.TrackNameProvider;
-import com.google.android.exoplayer2.upstream.DataSource;
-import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
-
-import com.google.android.exoplayer2.upstream.HttpDataSource;
+
+import androidx.media3.common.C;
+import androidx.media3.common.PlaybackException;
+import androidx.media3.database.StandaloneDatabaseProvider;
+import androidx.media3.datasource.DataSource;
+import androidx.media3.datasource.DefaultDataSource;
+import androidx.media3.datasource.HttpDataSource;
+import androidx.media3.datasource.cache.CacheDataSource;
+import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor;
+import androidx.media3.datasource.cache.SimpleCache;
+import androidx.media3.datasource.okhttp.OkHttpDataSource;
+import androidx.media3.exoplayer.DefaultLoadControl;
+import androidx.media3.exoplayer.DefaultRenderersFactory;
+import androidx.media3.common.Format;
+import androidx.media3.common.MediaItem;
+import androidx.media3.common.PlaybackParameters;
+import androidx.media3.common.Player;
+import androidx.media3.exoplayer.SeekParameters;
+import androidx.media3.exoplayer.ExoPlayer;
+import androidx.media3.common.AudioAttributes;
+import androidx.media3.exoplayer.source.MediaSource;
+import androidx.media3.exoplayer.source.ProgressiveMediaSource;
+import androidx.media3.exoplayer.source.TrackGroupArray;
+import androidx.media3.exoplayer.trackselection.DefaultTrackSelector;
+import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
+import androidx.media3.exoplayer.trackselection.MappingTrackSelector;
+import androidx.media3.exoplayer.trackselection.TrackSelectionArray;
+
+import androidx.media3.extractor.DefaultExtractorsFactory;
+import androidx.media3.extractor.mp3.Mp3Extractor;
+import androidx.media3.ui.DefaultTrackNameProvider;
+import androidx.media3.ui.TrackNameProvider;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.model.feed.VolumeAdaptionSetting;
@@ -47,7 +53,9 @@ import de.danoeh.antennapod.model.playback.Playable;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
+import okhttp3.Call;
+import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -58,11 +66,10 @@ public class ExoPlayerWrapper {
public static final int BUFFERING_STARTED = -1;
public static final int BUFFERING_ENDED = -2;
private static final String TAG = "ExoPlayerWrapper";
- public static final int ERROR_CODE_OFFSET = 1000;
private final Context context;
private final Disposable bufferingUpdateDisposable;
- private SimpleExoPlayer exoPlayer;
+ private ExoPlayer exoPlayer;
private MediaSource mediaSource;
private Runnable audioSeekCompleteListener;
private Runnable audioCompletionListener;
@@ -70,7 +77,7 @@ public class ExoPlayerWrapper {
private Consumer<Integer> bufferingUpdateListener;
private PlaybackParameters playbackParameters;
private DefaultTrackSelector trackSelector;
-
+ private SimpleCache simpleCache;
@Nullable
private LoudnessEnhancer loudnessEnhancer = null;
@@ -94,7 +101,7 @@ public class ExoPlayerWrapper {
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS);
loadControl.setBackBuffer(UserPreferences.getRewindSecs() * 1000 + 500, true);
trackSelector = new DefaultTrackSelector(context);
- exoPlayer = new SimpleExoPlayer.Builder(context, new DefaultRenderersFactory(context))
+ exoPlayer = new ExoPlayer.Builder(context, new DefaultRenderersFactory(context))
.setTrackSelector(trackSelector)
.setLoadControl(loadControl.build())
.build();
@@ -112,7 +119,7 @@ public class ExoPlayerWrapper {
}
@Override
- public void onPlayerError(@NonNull ExoPlaybackException error) {
+ public void onPlayerError(@NonNull PlaybackException error) {
if (audioErrorListener != null) {
if (NetworkUtils.wasDownloadBlocked(error)) {
audioErrorListener.accept(context.getString(R.string.download_error_blocked));
@@ -145,7 +152,8 @@ public class ExoPlayerWrapper {
initLoudnessEnhancer(audioSessionId);
}
});
-
+ simpleCache = new SimpleCache(new File(context.getCacheDir(), "streaming"),
+ new LeastRecentlyUsedCacheEvictor(50 * 1024 * 1024), new StandaloneDatabaseProvider(context));
initLoudnessEnhancer(exoPlayer.getAudioSessionId());
}
@@ -157,6 +165,10 @@ public class ExoPlayerWrapper {
return playbackParameters.speed;
}
+ public boolean getCurrentSkipSilence() {
+ return exoPlayer.getSkipSilenceEnabled();
+ }
+
public int getDuration() {
if (exoPlayer.getDuration() == C.TIME_UNSET) {
return Playable.INVALID_TIME;
@@ -182,6 +194,10 @@ public class ExoPlayerWrapper {
if (exoPlayer != null) {
exoPlayer.release();
}
+ if (simpleCache != null) {
+ simpleCache.release();
+ simpleCache = null;
+ }
audioSeekCompleteListener = null;
audioCompletionListener = null;
audioErrorListener = null;
@@ -190,6 +206,10 @@ public class ExoPlayerWrapper {
public void reset() {
exoPlayer.release();
+ if (simpleCache != null) {
+ simpleCache.release();
+ simpleCache = null;
+ }
createPlayer();
}
@@ -213,7 +233,7 @@ public class ExoPlayerWrapper {
throws IllegalArgumentException, IllegalStateException {
Log.d(TAG, "setDataSource: " + s);
final OkHttpDataSource.Factory httpDataSourceFactory =
- new OkHttpDataSource.Factory(AntennapodHttpClient.getHttpClient())
+ new OkHttpDataSource.Factory((Call.Factory) AntennapodHttpClient.getHttpClient())
.setUserAgent(ClientConfig.USER_AGENT);
if (!TextUtils.isEmpty(user) && !TextUtils.isEmpty(password)) {
@@ -224,7 +244,12 @@ public class ExoPlayerWrapper {
);
httpDataSourceFactory.setDefaultRequestProperties(requestProperties);
}
- DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context, null, httpDataSourceFactory);
+ DataSource.Factory dataSourceFactory = new DefaultDataSource.Factory(context, httpDataSourceFactory);
+ if (s.startsWith("http")) {
+ dataSourceFactory = new CacheDataSource.Factory()
+ .setCache(simpleCache)
+ .setUpstreamDataSourceFactory(httpDataSourceFactory);
+ }
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
extractorsFactory.setConstantBitrateSeekingEnabled(true);
extractorsFactory.setMp3ExtractorFlags(Mp3Extractor.FLAG_DISABLE_ID3_METADATA);
@@ -301,8 +326,8 @@ public class ExoPlayerWrapper {
}
TrackGroupArray trackGroups = trackInfo.getTrackGroups(getAudioRendererIndex());
DefaultTrackSelector.SelectionOverride override = new DefaultTrackSelector.SelectionOverride(track, 0);
- DefaultTrackSelector.ParametersBuilder params = trackSelector.buildUponParameters()
- .setSelectionOverride(getAudioRendererIndex(), trackGroups, override);
+ DefaultTrackSelector.Parameters params = trackSelector.buildUponParameters()
+ .setSelectionOverride(getAudioRendererIndex(), trackGroups, override).build();
trackSelector.setParameters(params);
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
index 69c632c4f..4c486c4d1 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
@@ -161,7 +161,9 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
try {
callback.ensureMediaInfoLoaded(media);
callback.onMediaChanged(false);
- setPlaybackParams(PlaybackSpeedUtils.getCurrentPlaybackSpeed(media), UserPreferences.isSkipSilence());
+ setPlaybackParams(PlaybackSpeedUtils.getCurrentPlaybackSpeed(media),
+ PlaybackSpeedUtils.getCurrentSkipSilencePreference(media)
+ == FeedPreferences.SkipSilence.AGGRESSIVE);
if (stream) {
if (playable instanceof FeedMedia) {
FeedMedia feedMedia = (FeedMedia) playable;
@@ -212,13 +214,14 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
Log.d(TAG, "Resuming/Starting playback");
acquireWifiLockIfNecessary();
- setPlaybackParams(PlaybackSpeedUtils.getCurrentPlaybackSpeed(media), UserPreferences.isSkipSilence());
+ setPlaybackParams(PlaybackSpeedUtils.getCurrentPlaybackSpeed(media),
+ PlaybackSpeedUtils.getCurrentSkipSilencePreference(media)
+ == FeedPreferences.SkipSilence.AGGRESSIVE);
setVolume(1.0f, 1.0f);
if (playerStatus == PlayerStatus.PREPARED && media.getPosition() > 0) {
int newPosition = RewindAfterPauseUtils.calculatePositionWithRewind(
- media.getPosition(),
- media.getLastPlayedTime());
+ media.getPosition(), media.getLastPlayedTime());
seekTo(newPosition);
}
mediaPlayer.start();
@@ -461,6 +464,18 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
return retVal;
}
+ @Override
+ public boolean getSkipSilence() {
+ boolean retVal = false;
+ if ((playerStatus == PlayerStatus.PLAYING
+ || playerStatus == PlayerStatus.PAUSED
+ || playerStatus == PlayerStatus.INITIALIZED
+ || playerStatus == PlayerStatus.PREPARED)) {
+ retVal = mediaPlayer.getCurrentSkipSilence();
+ }
+ return retVal;
+ }
+
/**
* Sets the playback volume.
* This method is executed on an internal executor service.
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
index 02102db14..067f8abff 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
@@ -129,6 +129,8 @@ public class PlaybackService extends MediaBrowserServiceCompat {
private static final String CUSTOM_ACTION_REWIND = "action.de.danoeh.antennapod.core.service.rewind";
private static final String CUSTOM_ACTION_CHANGE_PLAYBACK_SPEED =
"action.de.danoeh.antennapod.core.service.changePlaybackSpeed";
+ private static final String CUSTOM_ACTION_TOGGLE_SLEEP_TIMER =
+ "action.de.danoeh.antennapod.core.service.toggleSleepTimer";
public static final String CUSTOM_ACTION_NEXT_CHAPTER = "action.de.danoeh.antennapod.core.service.next_chapter";
/**
@@ -748,7 +750,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
}
if (!playable.getIdentifier().equals(PlaybackPreferences.getCurrentlyPlayingFeedMediaId())) {
- PlaybackPreferences.clearCurrentlyPlayingTemporaryPlaybackSpeed();
+ PlaybackPreferences.clearCurrentlyPlayingTemporaryPlaybackSettings();
}
mediaPlayer.playMediaObject(playable, stream, true, true);
@@ -977,6 +979,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
@SuppressWarnings("unused")
public void sleepTimerUpdate(SleepTimerUpdatedEvent event) {
if (event.isOver()) {
+ updateMediaSession(mediaPlayer.getPlayerStatus());
mediaPlayer.pause(true, true);
mediaPlayer.setVolume(1.0f, 1.0f);
int newPosition = mediaPlayer.getPosition() - (int) SleepTimer.NOTIFICATION_THRESHOLD / 2;
@@ -988,7 +991,10 @@ public class PlaybackService extends MediaBrowserServiceCompat {
Log.d(TAG, "onSleepTimerAlmostExpired: " + multiplicator);
mediaPlayer.setVolume(multiplicator, multiplicator);
} else if (event.isCancelled()) {
+ updateMediaSession(mediaPlayer.getPlayerStatus());
mediaPlayer.setVolume(1.0f, 1.0f);
+ } else if (event.wasJustEnabled()) {
+ updateMediaSession(mediaPlayer.getPlayerStatus());
}
}
@@ -1041,7 +1047,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
*/
private void onPlaybackEnded(MediaType mediaType, boolean stopPlaying) {
Log.d(TAG, "Playback ended");
- PlaybackPreferences.clearCurrentlyPlayingTemporaryPlaybackSpeed();
+ PlaybackPreferences.clearCurrentlyPlayingTemporaryPlaybackSettings();
if (stopPlaying) {
taskManager.cancelPositionSaver();
cancelPositionObserver();
@@ -1189,7 +1195,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
this.autoSkippedFeedMediaId = feedMedia.getItem().getIdentifyingValue();
mediaPlayer.skip();
}
- }
+ }
/**
* Updates the Media Session for the corresponding status.
@@ -1271,6 +1277,16 @@ public class PlaybackService extends MediaBrowserServiceCompat {
);
}
+ if (UserPreferences.showSleepTimerOnFullNotification()) {
+ @DrawableRes int icon = R.drawable.ic_notification_sleep;
+ if (sleepTimerActive()) {
+ icon = R.drawable.ic_notification_sleep_off;
+ }
+ sessionState.addCustomAction(
+ new PlaybackStateCompat.CustomAction.Builder(CUSTOM_ACTION_TOGGLE_SLEEP_TIMER,
+ getString(R.string.sleep_timer_label), icon).build());
+ }
+
if (UserPreferences.showNextChapterOnFullNotification()) {
if (getPlayable() != null && getPlayable().getChapters() != null) {
sessionState.addCustomAction(
@@ -1588,8 +1604,15 @@ public class PlaybackService extends MediaBrowserServiceCompat {
if (((FeedMedia) getPlayable()).getItem().getFeed().getId() == event.getFeedId()) {
if (event.getSpeed() == SPEED_USE_GLOBAL) {
setSpeed(UserPreferences.getPlaybackSpeed(getPlayable().getMediaType()));
+ setSkipSilence(UserPreferences.isSkipSilence());
} else {
setSpeed(event.getSpeed());
+ FeedPreferences.SkipSilence skipSilence = event.getSkipSilence();
+ if (skipSilence == FeedPreferences.SkipSilence.GLOBAL) {
+ setSkipSilence(UserPreferences.isSkipSilence());
+ } else {
+ setSkipSilence(skipSilence == FeedPreferences.SkipSilence.AGGRESSIVE);
+ }
}
}
}
@@ -1601,11 +1624,10 @@ public class PlaybackService extends MediaBrowserServiceCompat {
if (getPlayable() instanceof FeedMedia) {
if (((FeedMedia) getPlayable()).getItem().getFeed().getId() == event.getFeedId()) {
if (event.getSkipEnding() != 0) {
- FeedPreferences feedPreferences
- = ((FeedMedia) getPlayable()).getItem().getFeed().getPreferences();
- feedPreferences.setFeedSkipIntro(event.getSkipIntro());
- feedPreferences.setFeedSkipEnding(event.getSkipEnding());
-
+ FeedPreferences feedPreferences
+ = ((FeedMedia) getPlayable()).getItem().getFeed().getPreferences();
+ feedPreferences.setFeedSkipIntro(event.getSkipIntro());
+ feedPreferences.setFeedSkipEnding(event.getSkipEnding());
}
}
}
@@ -1653,20 +1675,29 @@ public class PlaybackService extends MediaBrowserServiceCompat {
UserPreferences.setPlaybackSpeed(speed);
}
- mediaPlayer.setPlaybackParams(speed, UserPreferences.isSkipSilence());
+ mediaPlayer.setPlaybackParams(speed, getCurrentSkipSilence());
}
- public void skipSilence(boolean skipSilence) {
+ public void setSkipSilence(boolean skipSilence) {
+ PlaybackPreferences.setCurrentlyPlayingTemporarySkipSilence(skipSilence);
+ UserPreferences.setSkipSilence(skipSilence);
mediaPlayer.setPlaybackParams(getCurrentPlaybackSpeed(), skipSilence);
}
public float getCurrentPlaybackSpeed() {
- if(mediaPlayer == null) {
+ if (mediaPlayer == null) {
return 1.0f;
}
return mediaPlayer.getPlaybackSpeed();
}
+ public boolean getCurrentSkipSilence() {
+ if (mediaPlayer == null) {
+ return false;
+ }
+ return mediaPlayer.getSkipSilence();
+ }
+
public boolean isStartWhenPrepared() {
return mediaPlayer.isStartWhenPrepared();
}
@@ -1950,6 +1981,12 @@ public class PlaybackService extends MediaBrowserServiceCompat {
}
onSetPlaybackSpeed(newSpeed);
}
+ } else if (CUSTOM_ACTION_TOGGLE_SLEEP_TIMER.equals(action)) {
+ if (sleepTimerActive()) {
+ disableSleepTimer();
+ } else {
+ setSleepTimer(SleepTimerPreferences.timerMillis());
+ }
}
}
};
diff --git a/core/src/play/java/de/danoeh/antennapod/core/service/playback/WearMediaSession.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/WearMediaSession.java
index 47881da0b..854562e2c 100644
--- a/core/src/play/java/de/danoeh/antennapod/core/service/playback/WearMediaSession.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/WearMediaSession.java
@@ -3,7 +3,6 @@ package de.danoeh.antennapod.core.service.playback;
import android.os.Bundle;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
-import android.support.wearable.media.MediaControlConstants;
public class WearMediaSession {
/**
@@ -12,14 +11,14 @@ public class WearMediaSession {
*/
static void addWearExtrasToAction(PlaybackStateCompat.CustomAction.Builder actionBuilder) {
Bundle actionExtras = new Bundle();
- actionExtras.putBoolean(MediaControlConstants.EXTRA_CUSTOM_ACTION_SHOW_ON_WEAR, true);
+ actionExtras.putBoolean("android.support.wearable.media.extra.CUSTOM_ACTION_SHOW_ON_WEAR", true);
actionBuilder.setExtras(actionExtras);
}
static void mediaSessionSetExtraForWear(MediaSessionCompat mediaSession) {
Bundle sessionExtras = new Bundle();
- sessionExtras.putBoolean(MediaControlConstants.EXTRA_RESERVE_SLOT_SKIP_TO_PREVIOUS, false);
- sessionExtras.putBoolean(MediaControlConstants.EXTRA_RESERVE_SLOT_SKIP_TO_NEXT, false);
+ sessionExtras.putBoolean("android.support.wearable.media.extra.RESERVE_SLOT_SKIP_TO_PREVIOUS", false);
+ sessionExtras.putBoolean("android.support.wearable.media.extra.RESERVE_SLOT_SKIP_TO_NEXT", false);
mediaSession.setExtras(sessionExtras);
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
index 492dff759..b390f5f44 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
@@ -736,9 +736,33 @@ public final class DBReader {
}
public static class MonthlyStatisticsItem {
- public int year = 0;
- public int month = 0;
- public long timePlayed = 0;
+ private int year = 0;
+ private int month = 0;
+ private long timePlayed = 0;
+
+ public int getYear() {
+ return year;
+ }
+
+ public void setYear(final int year) {
+ this.year = year;
+ }
+
+ public int getMonth() {
+ return month;
+ }
+
+ public void setMonth(final int month) {
+ this.month = month;
+ }
+
+ public long getTimePlayed() {
+ return timePlayed;
+ }
+
+ public void setTimePlayed(final long timePlayed) {
+ this.timePlayed = timePlayed;
+ }
}
@NonNull
@@ -752,9 +776,9 @@ public final class DBReader {
int indexTotalDuration = cursor.getColumnIndexOrThrow("total_duration");
while (cursor.moveToNext()) {
MonthlyStatisticsItem item = new MonthlyStatisticsItem();
- item.month = Integer.parseInt(cursor.getString(indexMonth));
- item.year = Integer.parseInt(cursor.getString(indexYear));
- item.timePlayed = cursor.getLong(indexTotalDuration);
+ item.setMonth(Integer.parseInt(cursor.getString(indexMonth)));
+ item.setYear(Integer.parseInt(cursor.getString(indexYear)));
+ item.setTimePlayed(cursor.getLong(indexTotalDuration));
months.add(item);
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
index d6a4fa1cb..d3b4ba6c6 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
@@ -197,6 +197,7 @@ public final class DBTasks {
public static synchronized Feed updateFeed(Context context, Feed newFeed, boolean removeUnlistedItems) {
Feed resultFeed;
List<FeedItem> unlistedItems = new ArrayList<>();
+ List<FeedItem> itemsToAddToQueue = new ArrayList<>();
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -242,8 +243,9 @@ public final class DBTasks {
FeedItem possibleDuplicate = searchFeedItemGuessDuplicate(newFeed.getItems(), item);
if (!newFeed.isLocalFeed() && possibleDuplicate != null && item != possibleDuplicate) {
// Canonical episode is the first one returned (usually oldest)
- DBWriter.addDownloadStatus(new DownloadResult(savedFeed,
- item.getTitle(), DownloadError.ERROR_PARSER_EXCEPTION_DUPLICATE, false,
+ DBWriter.addDownloadStatus(new DownloadResult(item.getTitle(),
+ savedFeed.getId(), Feed.FEEDFILETYPE_FEED, false,
+ DownloadError.ERROR_PARSER_EXCEPTION_DUPLICATE,
"The podcast host appears to have added the same episode twice. "
+ "AntennaPod still refreshed the feed and attempted to repair it."
+ "\n\nOriginal episode:\n" + duplicateEpisodeDetails(item)
@@ -257,8 +259,9 @@ public final class DBTasks {
oldItem = searchFeedItemGuessDuplicate(savedFeed.getItems(), item);
if (oldItem != null) {
Log.d(TAG, "Repaired duplicate: " + oldItem + ", " + item);
- DBWriter.addDownloadStatus(new DownloadResult(savedFeed,
- item.getTitle(), DownloadError.ERROR_PARSER_EXCEPTION_DUPLICATE, false,
+ DBWriter.addDownloadStatus(new DownloadResult(item.getTitle(),
+ savedFeed.getId(), Feed.FEEDFILETYPE_FEED, false,
+ DownloadError.ERROR_PARSER_EXCEPTION_DUPLICATE,
"The podcast host changed the ID of an existing episode instead of just "
+ "updating the episode itself. AntennaPod still refreshed the feed and "
+ "attempted to repair it."
@@ -290,18 +293,26 @@ public final class DBTasks {
savedFeed.getItems().add(idx, item);
}
- FeedPreferences.NewEpisodesAction action = savedFeed.getPreferences().getNewEpisodesAction();
- if (action == FeedPreferences.NewEpisodesAction.GLOBAL) {
- action = UserPreferences.getNewEpisodesAction();
- }
- if (action == FeedPreferences.NewEpisodesAction.ADD_TO_INBOX
- && (item.getPubDate() == null
- || priorMostRecentDate == null
- || priorMostRecentDate.before(item.getPubDate())
- || priorMostRecentDate.equals(item.getPubDate()))) {
- Log.d(TAG, "Marking item published on " + item.getPubDate()
- + " new, prior most recent date = " + priorMostRecentDate);
- item.setNew();
+ if (item.getPubDate() == null
+ || priorMostRecentDate == null
+ || priorMostRecentDate.before(item.getPubDate())
+ || priorMostRecentDate.equals(item.getPubDate())) {
+ Log.d(TAG, "Performing new episode action for item published on " + item.getPubDate()
+ + ", prior most recent date = " + priorMostRecentDate);
+ FeedPreferences.NewEpisodesAction action = savedFeed.getPreferences().getNewEpisodesAction();
+ if (action == FeedPreferences.NewEpisodesAction.GLOBAL) {
+ action = UserPreferences.getNewEpisodesAction();
+ }
+ switch (action) {
+ case ADD_TO_INBOX:
+ item.setNew();
+ break;
+ case ADD_TO_QUEUE:
+ itemsToAddToQueue.add(item);
+ break;
+ default:
+ break;
+ }
}
}
}
@@ -319,7 +330,7 @@ public final class DBTasks {
}
// update attributes
- savedFeed.setLastUpdate(newFeed.getLastUpdate());
+ savedFeed.setLastModified(newFeed.getLastModified());
savedFeed.setType(newFeed.getType());
savedFeed.setLastUpdateFailed(false);
@@ -341,6 +352,9 @@ public final class DBTasks {
e.printStackTrace();
}
+ // We need to add to queue after items are saved to database
+ DBWriter.addQueueItem(context, itemsToAddToQueue.toArray(new FeedItem[0]));
+
adapter.close();
if (savedFeed != null) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/NavDrawerData.java b/core/src/main/java/de/danoeh/antennapod/core/storage/NavDrawerData.java
index af02a7733..024c5d357 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/NavDrawerData.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/NavDrawerData.java
@@ -57,8 +57,8 @@ public class NavDrawerData {
public static class TagDrawerItem extends DrawerItem {
public final List<DrawerItem> children = new ArrayList<>();
- public final String name;
- public boolean isOpen;
+ private final String name;
+ private boolean isOpen;
public TagDrawerItem(String name) {
// Keep IDs >0 but make room for many feeds
@@ -70,6 +70,14 @@ public class NavDrawerData {
return name;
}
+ public boolean isOpen() {
+ return isOpen;
+ }
+
+ public void setOpen(final boolean open) {
+ isOpen = open;
+ }
+
public int getCounter() {
int sum = 0;
for (DrawerItem item : children) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/DateFormatter.java b/core/src/main/java/de/danoeh/antennapod/core/util/DateFormatter.java
index dc7ed4508..c67e13db3 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/DateFormatter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/DateFormatter.java
@@ -3,11 +3,9 @@ package de.danoeh.antennapod.core.util;
import android.content.Context;
import java.text.DateFormat;
-import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
-import java.util.Locale;
/**
* Formats dates.
@@ -17,11 +15,6 @@ public class DateFormatter {
}
- public static String formatRfc822Date(Date date) {
- SimpleDateFormat format = new SimpleDateFormat("dd MMM yy HH:mm:ss Z", Locale.US);
- return format.format(date);
- }
-
public static String formatAbbrev(final Context context, final Date date) {
if (date == null) {
return "";
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ReleaseScheduleGuesser.java b/core/src/main/java/de/danoeh/antennapod/core/util/ReleaseScheduleGuesser.java
new file mode 100644
index 000000000..580cf4164
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/ReleaseScheduleGuesser.java
@@ -0,0 +1,219 @@
+package de.danoeh.antennapod.core.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.List;
+
+/**
+ * Can be used to guess the release schedule of podcasts based on a sorted list of past release dates
+ */
+public class ReleaseScheduleGuesser {
+ static final long ONE_MINUTE = 60 * 1000;
+ static final long ONE_HOUR = ONE_MINUTE * 60;
+ static final long ONE_DAY = ONE_HOUR * 24;
+ static final long ONE_WEEK = ONE_DAY * 7;
+ static final long ONE_MONTH = ONE_DAY * 30;
+ private static final int MAX_DATA_POINTS = 20;
+
+ public enum Schedule {
+ DAILY, WEEKDAYS, SPECIFIC_DAYS,
+ WEEKLY, BIWEEKLY, FOURWEEKLY,
+ MONTHLY, UNKNOWN
+ }
+
+ public static class Guess {
+ public final Schedule schedule;
+ public final List<Integer> days;
+ public final Date nextExpectedDate;
+
+ public Guess(Schedule schedule, List<Integer> days, Date nextExpectedDate) {
+ this.schedule = schedule;
+ this.days = days;
+ this.nextExpectedDate = nextExpectedDate;
+ }
+ }
+
+ private static class Stats {
+ final float medianHour;
+ final float medianDistance;
+ final float avgDeltaToMedianDistance;
+ final int[] daysOfWeek;
+ final int[] daysOfMonth;
+ final int mostOftenDayOfWeek;
+ final int mostOftenDayOfMonth;
+
+ public Stats(float medianHour, float medianDistance, float avgDeltaToMedianDistance,
+ int[] daysOfWeek, int[] daysOfMonth, int mostOftenDayOfWeek, int mostOftenDayOfMonth) {
+ this.medianHour = medianHour;
+ this.medianDistance = medianDistance;
+ this.avgDeltaToMedianDistance = avgDeltaToMedianDistance;
+ this.daysOfWeek = daysOfWeek;
+ this.daysOfMonth = daysOfMonth;
+ this.mostOftenDayOfWeek = mostOftenDayOfWeek;
+ this.mostOftenDayOfMonth = mostOftenDayOfMonth;
+ }
+ }
+
+ private static void addTime(GregorianCalendar date, long time) {
+ date.setTime(new Date(date.getTime().getTime() + time));
+ }
+
+ private static void addUntil(GregorianCalendar date, List<Integer> days) {
+ do {
+ addTime(date, ONE_DAY);
+ } while (!days.contains(date.get(Calendar.DAY_OF_WEEK)));
+ }
+
+ private static <T> T getMedian(List<T> list) {
+ return list.get(list.size() / 2);
+ }
+
+ private static Stats getStats(List<Date> releaseDates) {
+ ArrayList<Float> hours = new ArrayList<>();
+ ArrayList<Long> distances = new ArrayList<>();
+ int[] daysOfWeek = new int[8];
+ int[] daysOfMonth = new int[32];
+ for (int i = 0; i < releaseDates.size(); i++) {
+ Date d = releaseDates.get(i);
+ Calendar calendar = new GregorianCalendar();
+ calendar.setTime(d);
+ hours.add(calendar.get(Calendar.HOUR_OF_DAY) + calendar.get(Calendar.MINUTE) / 60f);
+ if (i > 0) {
+ distances.add(d.getTime() - releaseDates.get(i - 1).getTime());
+ }
+ daysOfWeek[calendar.get(Calendar.DAY_OF_WEEK)]++;
+ daysOfMonth[calendar.get(Calendar.DAY_OF_MONTH)]++;
+ }
+
+ int mostOftenDayOfWeek = 1;
+ int mostOftenDayOfWeekNum = 0;
+ for (int i = Calendar.SUNDAY; i <= Calendar.SATURDAY; i++) {
+ if (daysOfWeek[i] > mostOftenDayOfWeekNum) {
+ mostOftenDayOfWeekNum = daysOfWeek[i];
+ mostOftenDayOfWeek = i;
+ }
+ }
+
+ int mostOftenDayOfMonth = 1;
+ int mostOftenDayOfMonthNum = 0;
+ for (int i = 1; i < 31; i++) {
+ if (daysOfMonth[i] > mostOftenDayOfMonthNum) {
+ mostOftenDayOfMonthNum = daysOfMonth[i];
+ mostOftenDayOfMonth = i;
+ }
+ }
+
+ Collections.sort(hours, Float::compareTo);
+ final float medianHour = getMedian(hours);
+ Collections.sort(distances, Long::compareTo);
+ final float medianDistance = getMedian(distances);
+
+ float avgDeltaToMedianDistance = 0;
+ for (long distance : distances) {
+ avgDeltaToMedianDistance += Math.abs(distance - medianDistance);
+ }
+ avgDeltaToMedianDistance /= distances.size();
+
+ return new Stats(medianHour, medianDistance, avgDeltaToMedianDistance,
+ daysOfWeek, daysOfMonth, mostOftenDayOfWeek, mostOftenDayOfMonth);
+ }
+
+ public static Guess performGuess(List<Date> releaseDates) {
+ if (releaseDates.size() <= 1) {
+ return new Guess(Schedule.UNKNOWN, null, null);
+ } else if (releaseDates.size() > MAX_DATA_POINTS) {
+ releaseDates = releaseDates.subList(releaseDates.size() - MAX_DATA_POINTS, releaseDates.size());
+ }
+ Stats stats = getStats(releaseDates);
+ final int maxTotalWrongDays = Math.max(1, releaseDates.size() / 5);
+ final int maxSingleDayOff = releaseDates.size() / 10;
+
+ GregorianCalendar last = new GregorianCalendar();
+ last.setTime(releaseDates.get(releaseDates.size() - 1));
+ last.set(Calendar.HOUR_OF_DAY, (int) stats.medianHour);
+ last.set(Calendar.MINUTE, (int) ((stats.medianHour - Math.floor(stats.medianHour)) * 60));
+ last.set(Calendar.SECOND, 0);
+ last.set(Calendar.MILLISECOND, 0);
+
+ if (Math.abs(stats.medianDistance - ONE_DAY) < 2 * ONE_HOUR
+ && stats.avgDeltaToMedianDistance < 2 * ONE_HOUR) {
+ addTime(last, ONE_DAY);
+ return new Guess(Schedule.DAILY, Arrays.asList(Calendar.MONDAY, Calendar.TUESDAY, Calendar.WEDNESDAY,
+ Calendar.THURSDAY, Calendar.FRIDAY, Calendar.SATURDAY, Calendar.SUNDAY), last.getTime());
+ } else if (Math.abs(stats.medianDistance - ONE_WEEK) < ONE_DAY
+ && stats.avgDeltaToMedianDistance < 2 * ONE_DAY) {
+ // Just using last.set(Calendar.DAY_OF_WEEK) could skip a week
+ // when the last release is delayed over week boundaries
+ addTime(last, 3 * ONE_DAY);
+ do {
+ addTime(last, ONE_DAY);
+ } while (last.get(Calendar.DAY_OF_WEEK) != stats.mostOftenDayOfWeek);
+ return new Guess(Schedule.WEEKLY, List.of(stats.mostOftenDayOfWeek), last.getTime());
+ } else if (Math.abs(stats.medianDistance - 2 * ONE_WEEK) < ONE_DAY
+ && stats.avgDeltaToMedianDistance < 2 * ONE_DAY) {
+ // Just using last.set(Calendar.DAY_OF_WEEK) could skip a week
+ // when the last release is delayed over week boundaries
+ addTime(last, 10 * ONE_DAY);
+ do {
+ addTime(last, ONE_DAY);
+ } while (last.get(Calendar.DAY_OF_WEEK) != stats.mostOftenDayOfWeek);
+ return new Guess(Schedule.BIWEEKLY, List.of(stats.mostOftenDayOfWeek), last.getTime());
+ } else if (Math.abs(stats.medianDistance - ONE_MONTH) < 5 * ONE_DAY
+ && stats.avgDeltaToMedianDistance < 5 * ONE_DAY) {
+ if (stats.daysOfMonth[stats.mostOftenDayOfMonth] >= releaseDates.size() - maxTotalWrongDays) {
+ // Just using last.set(Calendar.DAY_OF_MONTH) could skip a week
+ // when the last release is delayed over week boundaries
+ addTime(last, 2 * ONE_WEEK);
+ do {
+ addTime(last, ONE_DAY);
+ } while (last.get(Calendar.DAY_OF_MONTH) != stats.mostOftenDayOfMonth);
+ return new Guess(Schedule.MONTHLY, null, last.getTime());
+ }
+
+ addTime(last, 3 * ONE_WEEK + 3 * ONE_DAY);
+ do {
+ addTime(last, ONE_DAY);
+ } while (last.get(Calendar.DAY_OF_WEEK) != stats.mostOftenDayOfWeek);
+ return new Guess(Schedule.FOURWEEKLY, List.of(stats.mostOftenDayOfWeek), last.getTime());
+ }
+
+ // Find release days
+ List<Integer> largeDays = new ArrayList<>();
+ for (int i = Calendar.SUNDAY; i <= Calendar.SATURDAY; i++) {
+ if (stats.daysOfWeek[i] > maxSingleDayOff) {
+ largeDays.add(i);
+ }
+ }
+ // Ensure that all release days are used similarly often
+ int averageDays = releaseDates.size() / largeDays.size();
+ boolean matchesAverageDays = true;
+ for (int day : largeDays) {
+ if (stats.daysOfWeek[day] < averageDays - maxSingleDayOff) {
+ matchesAverageDays = false;
+ break;
+ }
+ }
+
+ if (matchesAverageDays && stats.medianDistance < ONE_WEEK) {
+ // Fixed daily release schedule (eg Mo, Thu, Fri)
+ addUntil(last, largeDays);
+
+ if (largeDays.size() == 5 && largeDays.containsAll(Arrays.asList(
+ Calendar.MONDAY, Calendar.TUESDAY, Calendar.WEDNESDAY, Calendar.THURSDAY, Calendar.FRIDAY))) {
+ return new Guess(Schedule.WEEKDAYS, largeDays, last.getTime());
+ }
+ return new Guess(Schedule.SPECIFIC_DAYS, largeDays, last.getTime());
+ } else if (largeDays.size() == 1) {
+ // Probably still weekly with more exceptions than others
+ addUntil(last, largeDays);
+ return new Guess(Schedule.WEEKLY, largeDays, last.getTime());
+ }
+
+ addTime(last, (long) (0.6f * stats.medianDistance));
+ return new Guess(Schedule.UNKNOWN, null, last.getTime());
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/download/ConnectionStateMonitor.java b/core/src/main/java/de/danoeh/antennapod/core/util/download/ConnectionStateMonitor.java
deleted file mode 100644
index a8d9437ee..000000000
--- a/core/src/main/java/de/danoeh/antennapod/core/util/download/ConnectionStateMonitor.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package de.danoeh.antennapod.core.util.download;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
-import android.util.Log;
-
-public class ConnectionStateMonitor
- extends ConnectivityManager.NetworkCallback
- implements ConnectivityManager.OnNetworkActiveListener {
- private static final String TAG = "ConnectionStateMonitor";
- final NetworkRequest networkRequest;
-
- public ConnectionStateMonitor() {
- networkRequest = new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .build();
- }
-
- @Override
- public void onNetworkActive() {
- Log.d(TAG, "ConnectionStateMonitor::onNetworkActive network connection changed");
- NetworkConnectionChangeHandler.networkChangedDetected();
- }
-
- public void enable(Context context) {
- ConnectivityManager connectivityManager =
- (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- connectivityManager.registerNetworkCallback(networkRequest, this);
- connectivityManager.addDefaultNetworkActiveListener(this);
- }
-
- public void disable(Context context) {
- ConnectivityManager connectivityManager =
- (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- connectivityManager.unregisterNetworkCallback(this);
- connectivityManager.removeDefaultNetworkActiveListener(this);
- }
-} \ No newline at end of file
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/download/NetworkConnectionChangeHandler.java b/core/src/main/java/de/danoeh/antennapod/core/util/download/NetworkConnectionChangeHandler.java
index 0547e353b..de2d8e9f4 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/download/NetworkConnectionChangeHandler.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/download/NetworkConnectionChangeHandler.java
@@ -1,13 +1,13 @@
package de.danoeh.antennapod.core.util.download;
import android.content.Context;
-import com.google.android.exoplayer2.util.Log;
+import android.util.Log;
import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.util.NetworkUtils;
public abstract class NetworkConnectionChangeHandler {
- private static final String TAG = "NetworkConnectionChangeHandler";
+ private static final String TAG = "NetConnChangeHandler";
private static Context context;
public static void init(Context context) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/MediaPlayerError.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/MediaPlayerError.java
deleted file mode 100644
index 8ca8bbf6c..000000000
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/MediaPlayerError.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package de.danoeh.antennapod.core.util.playback;
-
-import android.content.Context;
-import android.media.MediaPlayer;
-import com.google.android.exoplayer2.ExoPlaybackException;
-import de.danoeh.antennapod.core.R;
-import de.danoeh.antennapod.core.service.playback.ExoPlayerWrapper;
-
-/** Utility class for MediaPlayer errors. */
-public class MediaPlayerError {
- private MediaPlayerError(){}
-
- /** Get a human-readable string for a specific error code. */
- public static String getErrorString(Context context, int code) {
- int resId;
- switch (code) {
- case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
- resId = R.string.playback_error_server_died;
- break;
- case MediaPlayer.MEDIA_ERROR_UNSUPPORTED: // fall-through
- case ExoPlayerWrapper.ERROR_CODE_OFFSET + ExoPlaybackException.TYPE_RENDERER:
- resId = R.string.playback_error_unsupported;
- break;
- case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
- resId = R.string.playback_error_timeout;
- break;
- case ExoPlayerWrapper.ERROR_CODE_OFFSET + ExoPlaybackException.TYPE_SOURCE:
- resId = R.string.playback_error_source;
- break;
- default:
- resId = R.string.playback_error_unknown;
- break;
- }
- return context.getString(resId) + " (" + code + ")";
- }
-}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
index 2274dcf83..f17bd7e31 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
@@ -18,6 +18,7 @@ import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
import de.danoeh.antennapod.model.feed.FeedMedia;
import de.danoeh.antennapod.event.playback.PlaybackServiceEvent;
import de.danoeh.antennapod.event.playback.SpeedChangedEvent;
+import de.danoeh.antennapod.model.feed.FeedPreferences;
import de.danoeh.antennapod.model.playback.MediaType;
import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
@@ -407,7 +408,7 @@ public abstract class PlaybackController {
public void setSkipSilence(boolean skipSilence) {
if (playbackService != null) {
- playbackService.skipSilence(skipSilence);
+ playbackService.setSkipSilence(skipSilence);
}
}
@@ -419,6 +420,15 @@ public abstract class PlaybackController {
}
}
+ public boolean getCurrentPlaybackSkipSilence() {
+ if (playbackService != null) {
+ return playbackService.getCurrentSkipSilence();
+ } else {
+ return PlaybackSpeedUtils.getCurrentSkipSilencePreference(getMedia())
+ == FeedPreferences.SkipSilence.AGGRESSIVE;
+ }
+ }
+
public List<String> getAudioTracks() {
if (playbackService == null) {
return Collections.emptyList();
diff --git a/core/src/main/res/drawable-nodpi/teaser.png b/core/src/main/res/drawable-nodpi/teaser.png
deleted file mode 100644
index 61e3d919d..000000000
--- a/core/src/main/res/drawable-nodpi/teaser.png
+++ /dev/null
Binary files differ
diff --git a/core/src/main/res/drawable-nodpi/teaser.webp b/core/src/main/res/drawable-nodpi/teaser.webp
new file mode 100644
index 000000000..1f1e4a4a3
--- /dev/null
+++ b/core/src/main/res/drawable-nodpi/teaser.webp
Binary files differ
diff --git a/core/src/main/res/drawable/ic_eye.xml b/core/src/main/res/drawable/ic_eye.xml
new file mode 100644
index 000000000..b03875e4a
--- /dev/null
+++ b/core/src/main/res/drawable/ic_eye.xml
@@ -0,0 +1,5 @@
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
+ <path android:fillColor="?attr/action_icon_color" android:pathData="M12,9A3,3 0 0,1 15,12A3,3 0 0,1 12,15A3,3 0 0,1 9,12A3,3 0 0,1 12,9M12,4.5C17,4.5 21.27,7.61 23,12C21.27,16.39 17,19.5 12,19.5C7,19.5 2.73,16.39 1,12C2.73,7.61 7,4.5 12,4.5M3.18,12C4.83,15.36 8.24,17.5 12,17.5C15.76,17.5 19.17,15.36 20.82,12C19.17,8.64 15.76,6.5 12,6.5C8.24,6.5 4.83,8.64 3.18,12Z"/>
+</vector> \ No newline at end of file
diff --git a/core/src/main/res/values/arrays.xml b/core/src/main/res/values/arrays.xml
index 7eeab886a..a4f5d7f38 100644
--- a/core/src/main/res/values/arrays.xml
+++ b/core/src/main/res/values/arrays.xml
@@ -55,23 +55,27 @@
<string-array name="globalNewEpisodesActionItems">
<item>@string/feed_new_episodes_action_add_to_inbox</item>
+ <item>@string/feed_new_episodes_action_add_to_queue</item>
<item>@string/feed_new_episodes_action_nothing</item>
</string-array>
<string-array name="globalNewEpisodesActionValues">
<item>1</item>
+ <item>3</item>
<item>2</item>
</string-array>
<string-array name="feedNewEpisodesActionItems">
<item>@string/global_default</item>
<item>@string/feed_new_episodes_action_add_to_inbox</item>
+ <item>@string/feed_new_episodes_action_add_to_queue</item>
<item>@string/feed_new_episodes_action_nothing</item>
</string-array>
<string-array name="feedNewEpisodesActionValues">
<item>0</item>
<item>1</item>
+ <item>3</item>
<item>2</item>
</string-array>
@@ -250,6 +254,7 @@
<item>@string/skip_episode_label</item>
<item>@string/next_chapter</item>
<item>@string/playback_speed</item>
+ <item>@string/sleep_timer_label</item>
</string-array>
<string-array name="default_page_values">
diff --git a/core/src/test/java/android/text/TextUtils.java b/core/src/test/java/android/text/TextUtils.java
index eda31c3b5..709cb9e93 100644
--- a/core/src/test/java/android/text/TextUtils.java
+++ b/core/src/test/java/android/text/TextUtils.java
@@ -13,6 +13,7 @@ public class TextUtils {
* @param b second CharSequence to check
* @return true if a and b are equal
*/
+ @SuppressWarnings("unused")
public static boolean equals(CharSequence a, CharSequence b) {
if (a == b) return true;
int length;
diff --git a/core/src/test/java/de/danoeh/antennapod/core/storage/DbReaderTest.java b/core/src/test/java/de/danoeh/antennapod/core/storage/DbReaderTest.java
index b67bc48ea..e045012a6 100644
--- a/core/src/test/java/de/danoeh/antennapod/core/storage/DbReaderTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/storage/DbReaderTest.java
@@ -423,7 +423,10 @@ public class DbReaderTest {
FeedItem item2 = DBReader.getFeedItem(item1.getId());
item2.setChapters(DBReader.loadChaptersOfFeedItem(item2));
assertTrue(item2.hasChapters());
- assertEquals(item1.getChapters(), item2.getChapters());
+ assertEquals(item1.getChapters().size(), item2.getChapters().size());
+ for (int i = 0; i < item1.getChapters().size(); i++) {
+ assertEquals(item1.getChapters().get(i).getId(), item2.getChapters().get(i).getId());
+ }
}
@Test
diff --git a/core/src/test/java/de/danoeh/antennapod/core/storage/DbTasksTest.java b/core/src/test/java/de/danoeh/antennapod/core/storage/DbTasksTest.java
index 6a7e51bac..3eed90ea8 100644
--- a/core/src/test/java/de/danoeh/antennapod/core/storage/DbTasksTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/storage/DbTasksTest.java
@@ -252,25 +252,4 @@ public class DbTasksTest {
lastDate = item.getPubDate();
}
}
-
- private Feed createSavedFeed(String title, int numFeedItems) {
- final Feed feed = new Feed("url", null, title);
-
- if (numFeedItems > 0) {
- List<FeedItem> items = new ArrayList<>(numFeedItems);
- for (int i = 1; i <= numFeedItems; i++) {
- FeedItem item = new FeedItem(0, "item " + i + " of " + title, "id" + title + i, "link",
- new Date(), FeedItem.UNPLAYED, feed);
- items.add(item);
- }
- feed.setItems(items);
- }
-
- PodDBAdapter adapter = PodDBAdapter.getInstance();
- adapter.open();
- adapter.setCompleteFeed(feed);
- adapter.close();
- return feed;
- }
-
}
diff --git a/core/src/test/java/de/danoeh/antennapod/core/storage/ItemEnqueuePositionCalculatorTest.java b/core/src/test/java/de/danoeh/antennapod/core/storage/ItemEnqueuePositionCalculatorTest.java
index 2594fabf6..f0f81eee1 100644
--- a/core/src/test/java/de/danoeh/antennapod/core/storage/ItemEnqueuePositionCalculatorTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/storage/ItemEnqueuePositionCalculatorTest.java
@@ -16,7 +16,6 @@ import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
-import de.danoeh.antennapod.model.feed.FeedComponent;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.FeedMother;
@@ -145,7 +144,7 @@ public class ItemEnqueuePositionCalculatorTest {
Collections.unmodifiableList(Arrays.asList(
createFeedItem(11), createFeedItem(12), createFeedItem(13), createFeedItem(14)));
static final List<Long> QUEUE_DEFAULT_IDS =
- QUEUE_DEFAULT.stream().map(FeedComponent::getId).collect(Collectors.toList());
+ QUEUE_DEFAULT.stream().map(FeedItem::getId).collect(Collectors.toList());
static Playable getCurrentlyPlaying(long idCurrentlyPlaying) {
diff --git a/core/src/test/java/de/danoeh/antennapod/core/storage/mapper/FeedCursorMapperTest.java b/core/src/test/java/de/danoeh/antennapod/core/storage/mapper/FeedCursorMapperTest.java
index 486aa82a8..f41762672 100644
--- a/core/src/test/java/de/danoeh/antennapod/core/storage/mapper/FeedCursorMapperTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/storage/mapper/FeedCursorMapperTest.java
@@ -56,7 +56,7 @@ public class FeedCursorMapperTest {
assertEquals("feed file url", feed.getFile_url());
assertEquals("feed download url", feed.getDownload_url());
assertTrue(feed.isDownloaded());
- assertEquals("feed last update", feed.getLastUpdate());
+ assertEquals("feed last update", feed.getLastModified());
assertEquals("feed type", feed.getType());
assertEquals("feed identifier", feed.getFeedIdentifier());
assertTrue(feed.isPaged());
diff --git a/core/src/test/java/de/danoeh/antennapod/core/util/ReleaseScheduleGuesserRealWorldTest.java b/core/src/test/java/de/danoeh/antennapod/core/util/ReleaseScheduleGuesserRealWorldTest.java
new file mode 100644
index 000000000..dd3cd763b
--- /dev/null
+++ b/core/src/test/java/de/danoeh/antennapod/core/util/ReleaseScheduleGuesserRealWorldTest.java
@@ -0,0 +1,125 @@
+package de.danoeh.antennapod.core.util;
+
+import de.danoeh.antennapod.parser.feed.util.DateUtils;
+import org.apache.commons.io.IOUtils;
+import org.junit.Test;
+
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Locale;
+
+import static org.junit.Assert.assertTrue;
+
+public class ReleaseScheduleGuesserRealWorldTest {
+ private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.ROOT);
+
+ private void printHistogram(int[] histogram) {
+ int max = 0;
+ for (int x : histogram) {
+ max = Math.max(x, max);
+ }
+ for (int row = 8; row >= 0; row--) {
+ for (int x : histogram) {
+ System.out.print((x > (double) row * (max / 9.0)) ? "#" : " ");
+ }
+ System.out.println();
+ }
+ for (int col = 0; col < histogram.length; col++) {
+ System.out.print(((col % 5) == 0) ? "|" : " ");
+ }
+ System.out.println();
+ }
+
+ @Test
+ public void testRealWorld() throws Exception {
+ InputStream inputStream = getClass().getClassLoader().getResource("release_dates.csv").openStream();
+ int numCorrectDay = 0;
+ int numFoundSchedule = 0;
+ int numFoundScheduleAndCorrectDay = 0;
+ int num3hoursCorrect = 0;
+ int numOffByMoreThan2days = 0;
+ int[] histogram = new int[101];
+
+ String csv = IOUtils.toString(inputStream, "UTF-8");
+ String[] lines = csv.split("\n");
+ int totalPodcasts = 0;
+ int lineNr = 0;
+ for (String line : lines) {
+ lineNr++;
+ String[] dates = line.split(";");
+ List<Date> releaseDates = new ArrayList<>();
+ for (String date : dates) {
+ releaseDates.add(DateUtils.parse(date));
+ }
+ if (releaseDates.size() <= 3) {
+ continue;
+ }
+ totalPodcasts++;
+ Collections.sort(releaseDates, Comparator.comparingLong(Date::getTime));
+ Date dateActual = releaseDates.get(releaseDates.size() - 1);
+ // Remove most recent one and possible duplicates of episodes on the same day
+ do {
+ releaseDates = releaseDates.subList(0, releaseDates.size() - 1);
+ } while (releaseDates.get(releaseDates.size() - 1).getTime()
+ > dateActual.getTime() - 30 * ReleaseScheduleGuesser.ONE_MINUTE);
+ ReleaseScheduleGuesser.Guess guess = ReleaseScheduleGuesser.performGuess(releaseDates);
+
+ final boolean is3hoursClose = Math.abs(dateActual.getTime() - guess.nextExpectedDate.getTime())
+ < 3 * ReleaseScheduleGuesser.ONE_HOUR;
+ System.out.println(lineNr + " guessed: " + DATE_FORMAT.format(guess.nextExpectedDate)
+ + ", actual: " + DATE_FORMAT.format(dateActual)
+ + " " + guess.schedule.name() + (is3hoursClose ? " ✔" : ""));
+ long deltaTime = dateActual.getTime() - guess.nextExpectedDate.getTime();
+ int histogramClass = (int) Math.max(0, Math.min(100, deltaTime / ReleaseScheduleGuesser.ONE_HOUR + 50));
+ histogram[histogramClass]++;
+ boolean foundSchedule = guess.schedule != ReleaseScheduleGuesser.Schedule.UNKNOWN;
+ if (foundSchedule) {
+ numFoundSchedule++;
+ }
+ Calendar calendarExpected = new GregorianCalendar();
+ calendarExpected.setTime(dateActual);
+ Calendar calendarGuessed = new GregorianCalendar();
+ calendarGuessed.setTime(guess.nextExpectedDate);
+ if (calendarExpected.get(Calendar.DAY_OF_YEAR) == calendarGuessed.get(Calendar.DAY_OF_YEAR)) {
+ numCorrectDay++;
+ if (foundSchedule) {
+ numFoundScheduleAndCorrectDay++;
+ }
+ }
+ if (Math.abs(deltaTime) > 2 * ReleaseScheduleGuesser.ONE_DAY) {
+ numOffByMoreThan2days++;
+ }
+ if (is3hoursClose) {
+ num3hoursCorrect++;
+ }
+ }
+
+ System.out.println("Podcasts tested: " + totalPodcasts);
+
+ double schedulePercentage = 100.0 * numFoundSchedule / totalPodcasts;
+ System.out.println("Found schedule: " + schedulePercentage);
+ double offByLessThan3HoursPercentage = 100.0 * num3hoursCorrect / totalPodcasts;
+ System.out.println("Off by less than 3 hours: " + offByLessThan3HoursPercentage);
+ double scheduleAndCorrectDayPercentage = 100.0 * numFoundScheduleAndCorrectDay / numFoundSchedule;
+ System.out.println("Correct day when schedule found: " + scheduleAndCorrectDayPercentage);
+ double correctDayPercentage = 100.0 * numCorrectDay / totalPodcasts;
+ System.out.println("Correct day: " + correctDayPercentage);
+ double offByLessThan2daysPercentage = 100.0 * (totalPodcasts - numOffByMoreThan2days) / totalPodcasts;
+ System.out.println("Off by less than 2 days: " + offByLessThan2daysPercentage);
+
+ assertTrue(schedulePercentage > 80);
+ assertTrue(offByLessThan3HoursPercentage > 55);
+ assertTrue(scheduleAndCorrectDayPercentage > 75);
+ assertTrue(correctDayPercentage > 60);
+ assertTrue(offByLessThan2daysPercentage > 75);
+
+ printHistogram(histogram);
+ }
+} \ No newline at end of file
diff --git a/core/src/test/java/de/danoeh/antennapod/core/util/ReleaseScheduleGuesserTest.java b/core/src/test/java/de/danoeh/antennapod/core/util/ReleaseScheduleGuesserTest.java
new file mode 100644
index 000000000..aaad125c9
--- /dev/null
+++ b/core/src/test/java/de/danoeh/antennapod/core/util/ReleaseScheduleGuesserTest.java
@@ -0,0 +1,172 @@
+package de.danoeh.antennapod.core.util;
+
+import org.junit.Test;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Locale;
+
+import static de.danoeh.antennapod.core.util.ReleaseScheduleGuesser.ONE_DAY;
+import static de.danoeh.antennapod.core.util.ReleaseScheduleGuesser.ONE_HOUR;
+import static de.danoeh.antennapod.core.util.ReleaseScheduleGuesser.ONE_MINUTE;
+import static de.danoeh.antennapod.core.util.ReleaseScheduleGuesser.performGuess;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class ReleaseScheduleGuesserTest {
+ private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.ROOT);
+
+ private Date makeDate(String dateStr) {
+ try {
+ return DATE_FORMAT.parse(dateStr);
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void assertClose(Date expected, Date actual, long tolerance) {
+ assertTrue("Date should differ at most " + tolerance / 60000 + " minutes from "
+ + DATE_FORMAT.format(expected) + ", but is " + DATE_FORMAT.format(actual),
+ Math.abs(expected.getTime() - actual.getTime()) < tolerance);
+ }
+
+ @Test
+ public void testEdgeCases() {
+ ArrayList<Date> releaseDates = new ArrayList<>();
+ assertEquals(ReleaseScheduleGuesser.Schedule.UNKNOWN, performGuess(releaseDates).schedule);
+ releaseDates.add(makeDate("2024-01-01 16:30"));
+ assertEquals(ReleaseScheduleGuesser.Schedule.UNKNOWN, performGuess(releaseDates).schedule);
+ }
+
+ @Test
+ public void testDaily() {
+ ArrayList<Date> releaseDates = new ArrayList<>();
+ releaseDates.add(makeDate("2024-01-01 16:30")); // Monday
+ releaseDates.add(makeDate("2024-01-02 16:25"));
+ releaseDates.add(makeDate("2024-01-03 16:35"));
+ releaseDates.add(makeDate("2024-01-04 16:40"));
+ releaseDates.add(makeDate("2024-01-05 16:20"));
+ releaseDates.add(makeDate("2024-01-06 16:10"));
+ releaseDates.add(makeDate("2024-01-07 16:32")); // Sunday
+
+ // Next day
+ ReleaseScheduleGuesser.Guess guess = performGuess(releaseDates);
+ assertEquals(ReleaseScheduleGuesser.Schedule.DAILY, guess.schedule);
+ assertClose(makeDate("2024-01-08 16:30"), guess.nextExpectedDate, 10 * ONE_MINUTE);
+
+ // One-off early release
+ releaseDates.add(makeDate("2024-01-08 10:00"));
+ guess = performGuess(releaseDates);
+ assertEquals(ReleaseScheduleGuesser.Schedule.DAILY, guess.schedule);
+ assertClose(makeDate("2024-01-09 16:30"), guess.nextExpectedDate, 10 * ONE_MINUTE);
+ }
+
+ @Test
+ public void testWeekdays() {
+ ArrayList<Date> releaseDates = new ArrayList<>();
+ releaseDates.add(makeDate("2024-01-01 16:30")); // Monday
+ releaseDates.add(makeDate("2024-01-02 16:25"));
+ releaseDates.add(makeDate("2024-01-03 16:35"));
+ releaseDates.add(makeDate("2024-01-04 16:40"));
+ releaseDates.add(makeDate("2024-01-05 16:20")); // Friday
+ releaseDates.add(makeDate("2024-01-08 16:20")); // Monday
+ releaseDates.add(makeDate("2024-01-09 16:30"));
+ releaseDates.add(makeDate("2024-01-10 16:40"));
+ releaseDates.add(makeDate("2024-01-11 16:45")); // Thursday
+
+ // Next day
+ ReleaseScheduleGuesser.Guess guess = performGuess(releaseDates);
+ assertEquals(ReleaseScheduleGuesser.Schedule.WEEKDAYS, guess.schedule);
+ assertClose(makeDate("2024-01-12 16:30"), guess.nextExpectedDate, ONE_HOUR);
+
+ // After weekend
+ releaseDates.add(makeDate("2024-01-12 16:30")); // Friday
+ guess = performGuess(releaseDates);
+ assertClose(makeDate("2024-01-15 16:30"), guess.nextExpectedDate, ONE_HOUR);
+ }
+
+ @Test
+ public void testWeekly() {
+ ArrayList<Date> releaseDates = new ArrayList<>();
+ releaseDates.add(makeDate("2024-01-07 16:30")); // Sunday
+ releaseDates.add(makeDate("2024-01-14 16:25"));
+ releaseDates.add(makeDate("2024-01-21 14:25"));
+ releaseDates.add(makeDate("2024-01-28 16:15"));
+
+ // Next week
+ ReleaseScheduleGuesser.Guess guess = performGuess(releaseDates);
+ assertEquals(ReleaseScheduleGuesser.Schedule.WEEKLY, guess.schedule);
+ assertClose(makeDate("2024-02-04 16:30"), guess.nextExpectedDate, 2 * ONE_HOUR);
+
+ // One-off early release
+ releaseDates.add(makeDate("2024-02-02 16:35"));
+ guess = performGuess(releaseDates);
+ assertEquals(ReleaseScheduleGuesser.Schedule.WEEKLY, guess.schedule);
+ assertClose(makeDate("2024-02-11 16:30"), guess.nextExpectedDate, 2 * ONE_HOUR);
+
+ // One-off late release
+ releaseDates.add(makeDate("2024-02-13 16:35"));
+ guess = performGuess(releaseDates);
+ assertEquals(ReleaseScheduleGuesser.Schedule.WEEKLY, guess.schedule);
+ assertClose(makeDate("2024-02-18 16:30"), guess.nextExpectedDate, 2 * ONE_HOUR);
+ }
+
+ @Test
+ public void testMonthly() {
+ ArrayList<Date> releaseDates = new ArrayList<>();
+ releaseDates.add(makeDate("2024-01-01 16:30"));
+ releaseDates.add(makeDate("2024-02-01 16:30"));
+ releaseDates.add(makeDate("2024-03-01 16:30"));
+ releaseDates.add(makeDate("2024-04-01 16:30"));
+
+ // Next month
+ ReleaseScheduleGuesser.Guess guess = performGuess(releaseDates);
+ assertEquals(ReleaseScheduleGuesser.Schedule.MONTHLY, guess.schedule);
+ assertClose(makeDate("2024-05-01 16:30"), guess.nextExpectedDate, 10 * ONE_HOUR);
+
+ // One-off early release
+ releaseDates.add(makeDate("2024-04-30 16:30"));
+ guess = performGuess(releaseDates);
+ assertEquals(ReleaseScheduleGuesser.Schedule.MONTHLY, guess.schedule);
+ assertClose(makeDate("2024-06-01 16:30"), guess.nextExpectedDate, 10 * ONE_HOUR);
+
+ // One-off late release
+ releaseDates.remove(releaseDates.size() - 1);
+ releaseDates.add(makeDate("2024-05-13 16:30"));
+ guess = performGuess(releaseDates);
+ assertEquals(ReleaseScheduleGuesser.Schedule.MONTHLY, guess.schedule);
+ assertClose(makeDate("2024-06-01 16:30"), guess.nextExpectedDate, 10 * ONE_HOUR);
+ }
+
+ @Test
+ public void testFourweekly() {
+ ArrayList<Date> releaseDates = new ArrayList<>();
+ releaseDates.add(makeDate("2024-01-01 16:30"));
+ releaseDates.add(makeDate("2024-01-29 16:30"));
+ releaseDates.add(makeDate("2024-02-26 16:30"));
+ releaseDates.add(makeDate("2024-03-25 16:30"));
+
+ // 4 weeks later
+ ReleaseScheduleGuesser.Guess guess = performGuess(releaseDates);
+ assertEquals(ReleaseScheduleGuesser.Schedule.FOURWEEKLY, guess.schedule);
+ assertClose(makeDate("2024-04-22 16:30"), guess.nextExpectedDate, 10 * ONE_HOUR);
+ }
+
+ @Test
+ public void testUnknown() {
+ ArrayList<Date> releaseDates = new ArrayList<>();
+ releaseDates.add(makeDate("2024-01-01 16:30"));
+ releaseDates.add(makeDate("2024-01-03 16:30"));
+ releaseDates.add(makeDate("2024-01-03 16:31"));
+ releaseDates.add(makeDate("2024-01-04 16:30"));
+ releaseDates.add(makeDate("2024-01-04 16:31"));
+ releaseDates.add(makeDate("2024-01-07 16:30"));
+ releaseDates.add(makeDate("2024-01-07 16:31"));
+ releaseDates.add(makeDate("2024-01-10 16:30"));
+ ReleaseScheduleGuesser.Guess guess = performGuess(releaseDates);
+ assertEquals(ReleaseScheduleGuesser.Schedule.UNKNOWN, guess.schedule);
+ assertClose(makeDate("2024-01-12 16:30"), guess.nextExpectedDate, 2 * ONE_DAY);
+ }
+} \ No newline at end of file
diff --git a/core/src/test/resources/release_dates.csv b/core/src/test/resources/release_dates.csv
new file mode 100644
index 000000000..946b5dcab
--- /dev/null
+++ b/core/src/test/resources/release_dates.csv
@@ -0,0 +1,150 @@
+Fri, 16 Feb 2024 18:00:00 GMT;Thu, 15 Feb 2024 18:00:00 GMT;Wed, 14 Feb 2024 18:00:00 GMT;Tue, 13 Feb 2024 18:00:00 GMT;Fri, 09 Feb 2024 18:00:00 GMT;Wed, 07 Feb 2024 18:00:00 GMT;Tue, 06 Feb 2024 18:26:35 GMT;Fri, 02 Feb 2024 18:00:00 GMT;Thu, 01 Feb 2024 23:29:04 GMT;Wed, 31 Jan 2024 18:00:00 GMT;Tue, 30 Jan 2024 18:00:00 GMT;Fri, 26 Jan 2024 18:00:00 GMT;Thu, 25 Jan 2024 18:00:00 GMT;Wed, 24 Jan 2024 18:00:00 GMT;Tue, 23 Jan 2024 18:00:00 GMT;Sun, 21 Jan 2024 08:03:36 GMT;Sat, 20 Jan 2024 18:00:00 GMT;Fri, 19 Jan 2024 18:00:00 GMT;Thu, 18 Jan 2024 18:00:00 GMT;Tue, 16 Jan 2024 18:00:00 GMT;Fri, 12 Jan 2024 18:00:00 GMT;Thu, 11 Jan 2024 17:00:00 GMT;Wed, 10 Jan 2024 17:04:17 GMT;Tue, 09 Jan 2024 21:26:14 GMT;Thu, 04 Jan 2024 18:00:00 GMT;Wed, 03 Jan 2024 18:00:00 GMT;Tue, 02 Jan 2024 18:00:00 GMT;Thu, 28 Dec 2023 18:00:00 GMT;Wed, 27 Dec 2023 18:00:00 GMT;Tue, 26 Dec 2023 18:00:00 GMT;Thu, 21 Dec 2023 18:00:00 GMT;Wed, 20 Dec 2023 18:00:00 GMT;Tue, 19 Dec 2023 19:48:12 GMT;Thu, 14 Dec 2023 18:00:00 GMT;Wed, 13 Dec 2023 18:00:00 GMT;Tue, 12 Dec 2023 18:00:00 GMT;Thu, 07 Dec 2023 18:00:00 GMT;Wed, 06 Dec 2023 18:00:00 GMT;Tue, 05 Dec 2023 18:00:00 GMT;Thu, 30 Nov 2023 18:00:00 GMT;Wed, 29 Nov 2023 18:00:00 GMT;Tue, 28 Nov 2023 18:00:00 GMT;Sat, 25 Nov 2023 18:00:00 GMT;Thu, 23 Nov 2023 18:00:00 GMT;Wed, 22 Nov 2023 18:00:00 GMT;Tue, 21 Nov 2023 18:00:00 GMT;Thu, 16 Nov 2023 18:00:00 GMT;Wed, 15 Nov 2023 18:00:00 GMT;Tue, 14 Nov 2023 18:00:00 GMT;Fri, 10 Nov 2023 18:00:00 GMT
+Wed, 14 Feb 2024 11:20:00 -0000;Thu, 08 Feb 2024 10:45:00 -0000;Wed, 31 Jan 2024 10:55:00 -0000;Wed, 24 Jan 2024 10:55:00 -0000;Wed, 17 Jan 2024 10:59:00 -0000;Wed, 10 Jan 2024 10:50:00 -0000;Wed, 03 Jan 2024 11:30:00 -0000;Fri, 29 Dec 2023 11:00:00 -0000;Wed, 27 Dec 2023 10:57:00 -0000;Wed, 20 Dec 2023 10:59:00 -0000;Wed, 13 Dec 2023 10:50:00 -0000;Wed, 06 Dec 2023 10:55:00 -0000;Wed, 29 Nov 2023 10:55:00 -0000;Wed, 22 Nov 2023 11:00:00 -0000;Wed, 15 Nov 2023 10:55:00 -0000;Wed, 08 Nov 2023 10:55:00 -0000;Fri, 03 Nov 2023 10:00:00 -0000;Wed, 01 Nov 2023 10:06:00 -0000;Wed, 25 Oct 2023 10:05:00 -0000;Wed, 18 Oct 2023 09:50:00 -0000;Wed, 11 Oct 2023 10:09:00 -0000;Wed, 04 Oct 2023 09:55:00 -0000;Fri, 29 Sep 2023 09:50:00 -0000;Wed, 27 Sep 2023 10:00:00 -0000;Wed, 20 Sep 2023 10:10:00 -0000;Wed, 13 Sep 2023 09:50:00 -0000;Wed, 06 Sep 2023 09:50:00 -0000;Thu, 31 Aug 2023 22:09:00 -0000;Wed, 26 Jul 2023 09:50:00 -0000;Wed, 19 Jul 2023 09:50:00 -0000;Wed, 12 Jul 2023 14:39:16 -0000;Thu, 06 Jul 2023 09:50:00 -0000;Fri, 30 Jun 2023 12:00:00 -0000;Wed, 21 Jun 2023 09:50:00 -0000;Wed, 14 Jun 2023 21:55:00 -0000;Thu, 08 Jun 2023 03:00:00 -0000;Wed, 31 May 2023 20:15:00 -0000;Thu, 25 May 2023 09:50:00 -0000;Mon, 22 May 2023 09:50:00 -0000;Wed, 17 May 2023 09:50:00 -0000;Wed, 10 May 2023 09:55:00 -0000;Wed, 03 May 2023 10:00:00 -0000;Mon, 24 Apr 2023 09:58:00 -0000;Wed, 19 Apr 2023 09:50:00 -0000;Wed, 12 Apr 2023 09:50:00 -0000;Wed, 05 Apr 2023 10:00:00 -0000;Wed, 29 Mar 2023 21:27:00 -0000;Wed, 22 Mar 2023 10:00:00 -0000;Wed, 15 Mar 2023 22:00:00 -0000;Mon, 13 Mar 2023 10:00:00 -0000
+Thu, 15 Feb 2024 08:00:00 -0000;Mon, 12 Feb 2024 08:00:00 -0000;Thu, 11 Jan 2024 08:00:00 -0000;Mon, 08 Jan 2024 08:00:00 -0000;Thu, 04 Jan 2024 08:00:00 -0000;Mon, 01 Jan 2024 08:00:00 -0000;Thu, 28 Dec 2023 08:00:00 -0000;Thu, 28 Dec 2023 08:00:00 -0000;Thu, 21 Dec 2023 08:00:00 -0000;Mon, 18 Dec 2023 08:00:00 -0000;Thu, 14 Dec 2023 08:00:00 -0000;Mon, 11 Dec 2023 08:00:00 -0000;Thu, 07 Dec 2023 08:00:00 -0000;Mon, 04 Dec 2023 08:00:00 -0000;Thu, 30 Nov 2023 08:00:00 -0000;Mon, 27 Nov 2023 08:00:00 -0000;Thu, 23 Nov 2023 08:00:00 -0000;Mon, 20 Nov 2023 08:00:00 -0000;Thu, 16 Nov 2023 08:00:00 -0000;Mon, 13 Nov 2023 08:00:00 -0000;Thu, 09 Nov 2023 08:00:00 -0000;Mon, 06 Nov 2023 08:00:00 -0000;Thu, 02 Nov 2023 07:00:00 -0000;Mon, 30 Oct 2023 07:00:00 -0000;Thu, 26 Oct 2023 07:00:00 -0000;Mon, 23 Oct 2023 07:00:00 -0000;Thu, 19 Oct 2023 07:00:00 -0000;Mon, 16 Oct 2023 06:30:00 -0000;Thu, 12 Oct 2023 10:00:00 -0000;Mon, 09 Oct 2023 10:00:00 -0000;Thu, 05 Oct 2023 07:00:00 -0000;Mon, 02 Oct 2023 07:00:00 -0000;Thu, 28 Sep 2023 07:00:00 -0000;Mon, 25 Sep 2023 07:00:00 -0000;Thu, 21 Sep 2023 07:00:00 -0000;Mon, 18 Sep 2023 07:00:00 -0000;Thu, 14 Sep 2023 07:00:00 -0000;Mon, 11 Sep 2023 07:00:00 -0000;Thu, 07 Sep 2023 07:00:00 -0000;Mon, 04 Sep 2023 07:00:00 -0000;Thu, 31 Aug 2023 07:00:00 -0000;Mon, 28 Aug 2023 07:00:00 -0000;Thu, 24 Aug 2023 07:00:00 -0000;Mon, 21 Aug 2023 07:00:00 -0000;Mon, 21 Aug 2023 07:00:00 -0000;Mon, 14 Aug 2023 07:00:00 -0000;Thu, 10 Aug 2023 07:00:00 -0000;Tue, 08 Aug 2023 07:00:00 -0000;Mon, 07 Aug 2023 07:00:00 -0000;Thu, 03 Aug 2023 07:00:00 -0000
+Fri, 16 Feb 2024 12:00:00 -0000;Wed, 14 Feb 2024 12:00:00 -0000;Mon, 12 Feb 2024 12:00:00 -0000;Fri, 09 Feb 2024 12:00:00 -0000;Wed, 07 Feb 2024 12:00:00 -0000;Mon, 05 Feb 2024 12:00:00 -0000;Fri, 02 Feb 2024 12:00:00 -0000;Wed, 31 Jan 2024 12:00:00 -0000;Mon, 29 Jan 2024 12:00:00 -0000;Fri, 26 Jan 2024 12:00:00 -0000;Wed, 24 Jan 2024 12:00:00 -0000;Mon, 22 Jan 2024 12:00:00 -0000;Fri, 19 Jan 2024 12:00:00 -0000;Wed, 17 Jan 2024 12:00:00 -0000;Mon, 15 Jan 2024 12:00:00 -0000;Fri, 12 Jan 2024 12:00:00 -0000;Wed, 10 Jan 2024 12:00:00 -0000;Mon, 08 Jan 2024 12:00:00 -0000;Fri, 05 Jan 2024 12:00:00 -0000;Wed, 03 Jan 2024 12:00:00 -0000;Mon, 01 Jan 2024 12:00:00 -0000;Fri, 29 Dec 2023 12:00:00 -0000;Wed, 27 Dec 2023 12:00:00 -0000;Mon, 25 Dec 2023 12:00:00 -0000;Fri, 22 Dec 2023 12:00:00 -0000;Wed, 20 Dec 2023 12:00:00 -0000;Mon, 18 Dec 2023 12:00:00 -0000;Fri, 15 Dec 2023 12:00:00 -0000;Wed, 13 Dec 2023 12:00:00 -0000;Mon, 11 Dec 2023 12:00:00 -0000;Fri, 08 Dec 2023 12:00:00 -0000;Wed, 06 Dec 2023 12:00:00 -0000;Mon, 04 Dec 2023 12:00:00 -0000;Fri, 01 Dec 2023 12:00:00 -0000;Wed, 29 Nov 2023 12:00:00 -0000;Mon, 27 Nov 2023 12:00:00 -0000;Fri, 24 Nov 2023 12:00:00 -0000;Wed, 22 Nov 2023 12:00:00 -0000;Mon, 20 Nov 2023 12:00:00 -0000;Fri, 17 Nov 2023 12:00:00 -0000;Wed, 15 Nov 2023 12:00:00 -0000;Mon, 13 Nov 2023 12:00:00 -0000;Fri, 10 Nov 2023 12:00:00 -0000;Wed, 08 Nov 2023 12:00:00 -0000;Mon, 06 Nov 2023 12:00:00 -0000;Fri, 03 Nov 2023 11:00:00 -0000;Wed, 01 Nov 2023 11:00:00 -0000;Mon, 30 Oct 2023 11:00:00 -0000;Fri, 27 Oct 2023 11:00:00 -0000;Wed, 25 Oct 2023 11:00:00 -0000
+Sun, 18 Feb 2024 11:00:00 +0000;Fri, 16 Feb 2024 10:45:22 +0000;Thu, 15 Feb 2024 10:45:00 +0000;Wed, 14 Feb 2024 10:45:00 +0000;Tue, 13 Feb 2024 10:45:00 +0000;Mon, 12 Feb 2024 10:45:00 +0000;Sun, 11 Feb 2024 11:00:00 +0000;Fri, 9 Feb 2024 10:45:00 +0000;Thu, 8 Feb 2024 10:45:00 +0000;Wed, 7 Feb 2024 10:45:00 +0000;Tue, 6 Feb 2024 10:45:00 +0000;Mon, 5 Feb 2024 10:45:00 +0000;Sun, 4 Feb 2024 11:00:00 +0000;Fri, 2 Feb 2024 10:45:00 +0000;Thu, 1 Feb 2024 10:48:32 +0000;Wed, 31 Jan 2024 10:45:00 +0000;Tue, 30 Jan 2024 10:45:00 +0000;Mon, 29 Jan 2024 10:45:00 +0000;Sun, 28 Jan 2024 11:00:00 +0000;Fri, 26 Jan 2024 10:53:23 +0000;Thu, 25 Jan 2024 10:45:00 +0000;Wed, 24 Jan 2024 10:45:00 +0000;Tue, 23 Jan 2024 10:45:00 +0000;Mon, 22 Jan 2024 10:48:15 +0000;Sun, 21 Jan 2024 11:00:00 +0000;Fri, 19 Jan 2024 10:45:00 +0000;Thu, 18 Jan 2024 10:45:00 +0000;Wed, 17 Jan 2024 10:45:00 +0000;Tue, 16 Jan 2024 10:45:00 +0000;Sun, 14 Jan 2024 11:00:00 +0000;Fri, 12 Jan 2024 10:45:00 +0000;Thu, 11 Jan 2024 10:45:00 +0000;Wed, 10 Jan 2024 10:45:00 +0000;Tue, 9 Jan 2024 10:45:00 +0000;Mon, 8 Jan 2024 10:45:00 +0000;Sun, 7 Jan 2024 11:00:00 +0000;Fri, 5 Jan 2024 10:59:21 +0000;Thu, 4 Jan 2024 10:45:00 +0000;Wed, 3 Jan 2024 10:45:00 +0000;Tue, 2 Jan 2024 10:45:00 +0000;Fri, 29 Dec 2023 10:45:00 +0000;Thu, 28 Dec 2023 10:45:00 +0000;Wed, 27 Dec 2023 10:45:00 +0000;Tue, 26 Dec 2023 10:45:00 +0000;Fri, 22 Dec 2023 10:45:00 +0000;Thu, 21 Dec 2023 10:45:00 +0000;Wed, 20 Dec 2023 10:45:00 +0000;Tue, 19 Dec 2023 10:45:05 +0000;Mon, 18 Dec 2023 10:45:00 +0000;Sun, 17 Dec 2023 11:00:00 +0000
+Wed, 14 Feb 2024 11:00:00 +0000;Tue, 13 Feb 2024 11:00:00 +0000;Wed, 7 Feb 2024 11:00:00 +0000;Tue, 6 Feb 2024 11:00:00 +0000;Wed, 31 Jan 2024 11:00:00 +0000;Tue, 30 Jan 2024 11:00:00 +0000;Wed, 24 Jan 2024 11:00:00 +0000;Tue, 23 Jan 2024 11:00:00 +0000;Wed, 17 Jan 2024 11:00:00 +0000;Tue, 16 Jan 2024 11:00:00 +0000;Wed, 10 Jan 2024 11:00:00 +0000;Tue, 9 Jan 2024 11:00:00 +0000;Wed, 3 Jan 2024 11:00:00 +0000;Tue, 2 Jan 2024 11:00:00 +0000;Wed, 27 Dec 2023 11:00:00 +0000;Tue, 26 Dec 2023 11:00:00 +0000;Sat, 23 Dec 2023 11:00:00 +0000;Thu, 21 Dec 2023 13:00:00 +0000;Wed, 20 Dec 2023 13:00:00 +0000;Wed, 20 Dec 2023 11:00:00 +0000;Tue, 19 Dec 2023 13:00:00 +0000;Tue, 19 Dec 2023 11:00:00 +0000;Wed, 13 Dec 2023 11:00:00 +0000;Tue, 12 Dec 2023 11:00:00 +0000;Wed, 6 Dec 2023 11:00:00 +0000;Tue, 5 Dec 2023 11:00:00 +0000;Wed, 29 Nov 2023 11:00:00 +0000;Tue, 28 Nov 2023 11:00:00 +0000;Wed, 22 Nov 2023 11:00:00 +0000;Tue, 21 Nov 2023 11:00:00 +0000;Wed, 15 Nov 2023 11:00:00 +0000;Tue, 14 Nov 2023 11:00:00 +0000;Wed, 8 Nov 2023 11:00:00 +0000;Tue, 7 Nov 2023 11:00:00 +0000;Wed, 1 Nov 2023 10:00:00 +0000;Tue, 31 Oct 2023 10:00:00 +0000;Wed, 25 Oct 2023 10:00:00 +0000;Tue, 24 Oct 2023 10:00:00 +0000;Wed, 18 Oct 2023 10:00:00 +0000;Tue, 17 Oct 2023 10:00:00 +0000;Wed, 11 Oct 2023 10:00:00 +0000;Tue, 10 Oct 2023 10:00:00 +0000;Wed, 4 Oct 2023 10:00:00 +0000;Tue, 3 Oct 2023 10:00:00 +0000;Thu, 28 Sep 2023 10:00:00 +0000;Wed, 27 Sep 2023 10:00:00 +0000;Tue, 26 Sep 2023 10:00:00 +0000;Wed, 20 Sep 2023 10:00:00 +0000;Tue, 19 Sep 2023 10:00:00 +0000;Wed, 13 Sep 2023 10:00:00 +0000
+Sun, 18 Feb 2024 08:30:00 +0000;Sat, 17 Feb 2024 08:30:00 +0000;Fri, 16 Feb 2024 08:30:00 +0000;Thu, 15 Feb 2024 08:30:00 +0000;Wed, 14 Feb 2024 08:30:00 +0000;Tue, 13 Feb 2024 08:30:00 +0000;Mon, 12 Feb 2024 08:30:00 +0000;Sun, 11 Feb 2024 08:30:00 +0000;Sat, 10 Feb 2024 08:30:00 +0000;Fri, 09 Feb 2024 08:30:00 +0000;Thu, 08 Feb 2024 08:30:00 +0000;Wed, 07 Feb 2024 08:30:00 +0000;Tue, 06 Feb 2024 08:30:00 +0000;Mon, 05 Feb 2024 08:30:00 +0000;Fri, 02 Feb 2024 08:30:00 +0000;Thu, 01 Feb 2024 08:30:00 +0000;Wed, 31 Jan 2024 08:30:00 +0000;Tue, 30 Jan 2024 08:30:00 +0000;Mon, 29 Jan 2024 08:30:00 +0000;Fri, 26 Jan 2024 08:30:00 +0000;Thu, 25 Jan 2024 08:30:00 +0000;Wed, 24 Jan 2024 08:30:00 +0000;Tue, 23 Jan 2024 08:30:00 +0000;Mon, 22 Jan 2024 08:30:00 +0000;Fri, 19 Jan 2024 08:30:00 +0000;Thu, 18 Jan 2024 08:30:00 +0000;Wed, 17 Jan 2024 08:30:00 +0000;Tue, 16 Jan 2024 08:30:00 +0000;Mon, 15 Jan 2024 08:30:00 +0000;Fri, 12 Jan 2024 08:30:00 +0000;Thu, 11 Jan 2024 08:30:00 +0000;Wed, 10 Jan 2024 08:30:00 +0000;Tue, 09 Jan 2024 08:30:00 +0000;Mon, 08 Jan 2024 08:30:00 +0000;Sun, 07 Jan 2024 08:30:00 +0000;Sat, 06 Jan 2024 08:30:00 +0000;Fri, 05 Jan 2024 08:30:00 +0000;Thu, 04 Jan 2024 08:30:00 +0000;Wed, 03 Jan 2024 08:30:00 +0000;Tue, 02 Jan 2024 08:30:00 +0000;Mon, 01 Jan 2024 08:30:00 +0000;Sun, 31 Dec 2023 08:30:00 +0000;Sat, 30 Dec 2023 08:30:00 +0000;Fri, 29 Dec 2023 08:30:00 +0000;Thu, 28 Dec 2023 08:30:00 +0000;Wed, 27 Dec 2023 08:30:00 +0000;Tue, 26 Dec 2023 08:30:00 +0000;Mon, 25 Dec 2023 08:30:00 +0000;Sun, 24 Dec 2023 08:30:00 +0000;Sat, 23 Dec 2023 08:30:00 +0000
+Fri, 16 Feb 2024 07:30:00 -0000;Wed, 14 Feb 2024 07:30:00 -0000;Sun, 11 Feb 2024 13:00:00 -0000;Wed, 07 Feb 2024 07:30:00 -0000;Sun, 04 Feb 2024 13:00:00 -0000;Wed, 31 Jan 2024 07:30:00 -0000;Wed, 24 Jan 2024 07:30:00 -0000;Sun, 21 Jan 2024 13:00:00 -0000;Wed, 17 Jan 2024 07:30:00 -0000;Wed, 10 Jan 2024 07:30:00 -0000;Sun, 07 Jan 2024 13:00:00 -0000;Wed, 03 Jan 2024 07:30:00 -0000;Wed, 27 Dec 2023 07:30:00 -0000;Sun, 24 Dec 2023 13:00:00 -0000;Wed, 20 Dec 2023 07:30:00 -0000;Wed, 13 Dec 2023 07:30:00 -0000;Sun, 10 Dec 2023 13:00:00 -0000;Wed, 06 Dec 2023 07:30:00 -0000;Wed, 29 Nov 2023 07:30:00 -0000;Wed, 22 Nov 2023 07:35:00 -0000;Wed, 15 Nov 2023 07:35:00 -0000;Wed, 08 Nov 2023 07:35:00 -0000;Sun, 05 Nov 2023 13:00:00 -0000;Wed, 01 Nov 2023 06:35:00 -0000;Sun, 29 Oct 2023 12:00:00 -0000;Wed, 25 Oct 2023 06:35:00 -0000;Sun, 22 Oct 2023 12:00:00 -0000;Wed, 18 Oct 2023 06:35:00 -0000;Wed, 11 Oct 2023 06:35:00 -0000;Sun, 08 Oct 2023 12:00:00 -0000;Wed, 04 Oct 2023 06:35:00 -0000;Sun, 01 Oct 2023 12:00:00 -0000;Wed, 27 Sep 2023 06:35:00 -0000;Sun, 24 Sep 2023 12:00:00 -0000;Wed, 20 Sep 2023 07:00:00 -0000;Wed, 13 Sep 2023 01:00:00 -0000;Wed, 06 Sep 2023 18:22:00 -0000;Wed, 30 Aug 2023 01:00:00 -0000;Wed, 23 Aug 2023 01:00:00 -0000;Sun, 20 Aug 2023 12:00:00 -0000;Wed, 16 Aug 2023 01:00:00 -0000;Wed, 09 Aug 2023 01:06:00 -0000;Sun, 06 Aug 2023 12:00:00 -0000;Wed, 02 Aug 2023 02:06:00 -0000;Sun, 30 Jul 2023 12:00:00 -0000;Wed, 26 Jul 2023 01:00:00 -0000;Wed, 19 Jul 2023 01:00:00 -0000;Wed, 12 Jul 2023 03:00:00 -0000;Wed, 28 Jun 2023 00:47:00 -0000;Sun, 25 Jun 2023 12:00:00 -0000
+Mon, 12 Feb 2024 08:00:00 +0000;Tue, 6 Feb 2024 08:00:00 +0000;Mon, 5 Feb 2024 08:00:00 +0000;Mon, 29 Jan 2024 08:00:00 +0000;Mon, 22 Jan 2024 08:00:00 +0000;Mon, 15 Jan 2024 08:00:00 +0000;Tue, 9 Jan 2024 22:00:00 +0000;Mon, 8 Jan 2024 08:05:00 +0000;Mon, 8 Jan 2024 08:00:00 +0000;Thu, 4 Jan 2024 08:00:00 +0000;Mon, 1 Jan 2024 08:00:00 +0000;Mon, 25 Dec 2023 08:05:00 +0000;Mon, 25 Dec 2023 08:00:00 +0000;Mon, 18 Dec 2023 08:00:00 +0000;Mon, 18 Dec 2023 08:00:00 +0000;Mon, 11 Dec 2023 08:00:00 +0000;Mon, 4 Dec 2023 08:00:00 +0000;Mon, 27 Nov 2023 08:00:00 +0000;Mon, 20 Nov 2023 08:00:00 +0000;Mon, 13 Nov 2023 08:00:00 +0000;Mon, 6 Nov 2023 08:00:00 +0000;Mon, 30 Oct 2023 07:00:00 +0000;Mon, 23 Oct 2023 07:00:00 +0000;Mon, 16 Oct 2023 07:00:00 +0000;Tue, 10 Oct 2023 07:00:00 +0000;Mon, 9 Oct 2023 07:00:00 +0000;Mon, 2 Oct 2023 07:00:00 +0000;Mon, 25 Sep 2023 07:00:00 +0000;Mon, 18 Sep 2023 07:00:00 +0000;Mon, 11 Sep 2023 07:00:00 +0000;Mon, 4 Sep 2023 07:00:00 +0000;Mon, 28 Aug 2023 07:00:00 +0000;Fri, 25 Aug 2023 13:05:00 +0000;Mon, 21 Aug 2023 07:00:00 +0000;Mon, 14 Aug 2023 07:00:00 +0000;Mon, 7 Aug 2023 07:00:00 +0000;Mon, 31 Jul 2023 07:00:00 +0000;Fri, 28 Jul 2023 00:05:00 +0000;Mon, 24 Jul 2023 07:00:00 +0000;Mon, 17 Jul 2023 07:00:00 +0000;Mon, 10 Jul 2023 07:00:00 +0000;Mon, 3 Jul 2023 07:00:00 +0000;Mon, 26 Jun 2023 07:00:00 +0000;Mon, 19 Jun 2023 07:00:00 +0000;Mon, 12 Jun 2023 07:00:00 +0000;Mon, 5 Jun 2023 07:00:00 +0000;Mon, 29 May 2023 07:00:00 +0000;Mon, 22 May 2023 07:00:00 +0000;Mon, 15 May 2023 07:00:00 +0000;Mon, 8 May 2023 07:00:00 +0000
+Mon, 12 Feb 2024 10:00:00 -0000;Mon, 05 Feb 2024 10:00:00 -0000;Mon, 05 Feb 2024 10:00:00 -0000;Thu, 04 Jan 2024 21:38:00 -0000
+Mon, 12 Feb 2024 09:00:00 -0000;Mon, 05 Feb 2024 09:00:00 -0000;Thu, 01 Feb 2024 01:20:00 -0000;Mon, 29 Jan 2024 09:00:00 -0000;Mon, 22 Jan 2024 09:00:00 -0000;Mon, 15 Jan 2024 09:00:00 -0000;Mon, 08 Jan 2024 09:00:00 -0000;Mon, 01 Jan 2024 09:00:00 -0000;Sun, 31 Dec 2023 20:45:00 -0000;Mon, 25 Dec 2023 09:00:00 -0000;Mon, 18 Dec 2023 09:00:00 -0000;Wed, 13 Dec 2023 09:00:00 -0000;Mon, 11 Dec 2023 09:00:00 -0000;Mon, 04 Dec 2023 09:00:00 -0000;Thu, 30 Nov 2023 13:00:00 -0000;Mon, 27 Nov 2023 09:00:00 -0000;Mon, 20 Nov 2023 09:00:00 -0000;Wed, 15 Nov 2023 09:00:00 -0000;Mon, 13 Nov 2023 09:00:00 -0000;Mon, 06 Nov 2023 09:00:00 -0000;Tue, 31 Oct 2023 18:08:58 -0000;Mon, 30 Oct 2023 08:00:00 -0000;Mon, 23 Oct 2023 08:00:00 -0000;Mon, 16 Oct 2023 08:00:00 -0000;Mon, 09 Oct 2023 08:00:00 -0000;Mon, 02 Oct 2023 08:00:00 -0000;Fri, 29 Sep 2023 12:00:00 -0000;Wed, 27 Sep 2023 08:00:00 -0000;Mon, 25 Sep 2023 08:00:00 -0000;Wed, 20 Sep 2023 08:00:00 -0000;Mon, 18 Sep 2023 08:00:00 -0000;Wed, 13 Sep 2023 08:00:00 -0000;Mon, 11 Sep 2023 08:00:00 -0000;Wed, 06 Sep 2023 08:00:00 -0000;Mon, 04 Sep 2023 08:00:00 -0000;Wed, 30 Aug 2023 12:00:00 -0000;Mon, 28 Aug 2023 08:00:00 -0000;Mon, 21 Aug 2023 08:00:00 -0000;Mon, 14 Aug 2023 08:00:00 -0000;Mon, 07 Aug 2023 08:00:00 -0000;Mon, 31 Jul 2023 08:00:00 -0000;Fri, 28 Jul 2023 12:00:00 -0000;Mon, 24 Jul 2023 08:00:00 -0000;Mon, 17 Jul 2023 08:00:00 -0000;Mon, 10 Jul 2023 08:00:00 -0000;Mon, 03 Jul 2023 08:00:00 -0000;Mon, 26 Jun 2023 08:00:00 -0000;Fri, 23 Jun 2023 17:00:00 -0000;Mon, 19 Jun 2023 08:00:00 -0000;Mon, 12 Jun 2023 08:00:00 -0000
+Thu, 15 Feb 2024 08:01:00 -0000;Mon, 12 Feb 2024 08:01:00 -0000;Thu, 08 Feb 2024 08:01:00 -0000;Mon, 05 Feb 2024 08:01:00 -0000;Thu, 01 Feb 2024 08:01:00 -0000;Mon, 29 Jan 2024 08:01:00 -0000;Thu, 25 Jan 2024 08:01:00 -0000;Tue, 23 Jan 2024 13:00:00 -0000;Mon, 22 Jan 2024 08:01:00 -0000;Thu, 18 Jan 2024 08:01:00 -0000;Mon, 15 Jan 2024 08:01:00 -0000;Thu, 11 Jan 2024 08:01:00 -0000;Mon, 08 Jan 2024 08:01:00 -0000;Thu, 04 Jan 2024 08:01:00 -0000;Mon, 01 Jan 2024 08:01:00 -0000;Thu, 28 Dec 2023 08:01:00 -0000;Mon, 25 Dec 2023 08:01:00 -0000;Thu, 21 Dec 2023 08:01:00 -0000;Mon, 18 Dec 2023 08:01:00 -0000;Thu, 14 Dec 2023 08:00:00 -0000;Mon, 11 Dec 2023 08:01:00 -0000;Thu, 07 Dec 2023 08:01:00 -0000;Mon, 04 Dec 2023 08:00:00 -0000;Thu, 30 Nov 2023 08:01:00 -0000;Mon, 27 Nov 2023 08:01:00 -0000;Thu, 23 Nov 2023 08:00:00 -0000;Mon, 20 Nov 2023 08:00:00 -0000;Thu, 16 Nov 2023 08:00:00 -0000;Mon, 13 Nov 2023 08:00:00 -0000;Thu, 09 Nov 2023 08:00:00 -0000;Mon, 06 Nov 2023 08:00:00 -0000;Thu, 02 Nov 2023 07:00:00 -0000;Mon, 30 Oct 2023 07:00:00 -0000;Thu, 26 Oct 2023 07:00:00 -0000;Mon, 23 Oct 2023 07:00:00 -0000;Thu, 19 Oct 2023 07:00:00 -0000;Mon, 16 Oct 2023 07:00:00 -0000;Thu, 12 Oct 2023 07:00:00 -0000;Mon, 09 Oct 2023 07:00:00 -0000;Thu, 05 Oct 2023 07:00:00 -0000;Mon, 02 Oct 2023 07:00:00 -0000;Thu, 28 Sep 2023 07:00:00 -0000;Mon, 25 Sep 2023 07:00:00 -0000;Thu, 21 Sep 2023 07:00:00 -0000;Mon, 18 Sep 2023 07:00:00 -0000;Thu, 14 Sep 2023 07:00:00 -0000;Mon, 11 Sep 2023 07:00:00 -0000;Thu, 07 Sep 2023 07:01:00 -0000;Mon, 04 Sep 2023 07:01:00 -0000;Thu, 31 Aug 2023 07:00:00 -0000
+Sat, 17 Feb 2024 17:45:03 GMT;Fri, 16 Feb 2024 17:00:40 GMT;Thu, 15 Feb 2024 18:20:08 GMT;Wed, 14 Feb 2024 18:04:07 GMT;Tue, 13 Feb 2024 19:21:35 GMT;Mon, 12 Feb 2024 19:13:41 GMT;Sun, 11 Feb 2024 21:40:34 GMT;Sat, 10 Feb 2024 08:26:52 GMT;Sat, 05 Mar 2022 02:17:00 GMT
+Sun, 18 Feb 2024 08:00:00 +0000;Fri, 16 Feb 2024 08:00:00 +0000;Wed, 14 Feb 2024 22:54:59 +0000;Tue, 13 Feb 2024 08:00:00 +0000;Fri, 9 Feb 2024 08:00:00 +0000;Thu, 8 Feb 2024 00:52:39 +0000;Tue, 6 Feb 2024 08:00:00 +0000;Fri, 2 Feb 2024 08:00:00 +0000;Wed, 31 Jan 2024 21:35:23 +0000;Tue, 30 Jan 2024 08:00:00 +0000;Fri, 26 Jan 2024 08:00:00 +0000;Wed, 24 Jan 2024 08:00:00 +0000;Tue, 23 Jan 2024 07:55:00 +0000;Fri, 19 Jan 2024 08:00:00 +0000;Wed, 17 Jan 2024 21:27:10 +0000;Tue, 16 Jan 2024 08:12:46 +0000;Fri, 12 Jan 2024 08:00:00 +0000;Wed, 10 Jan 2024 08:00:00 +0000;Tue, 9 Jan 2024 08:00:00 +0000;Thu, 4 Jan 2024 22:16:52 +0000;Thu, 28 Dec 2023 08:00:00 +0000;Tue, 26 Dec 2023 08:00:00 +0000;Thu, 21 Dec 2023 08:00:00 +0000;Tue, 19 Dec 2023 08:00:00 +0000;Thu, 14 Dec 2023 17:47:02 +0000;Tue, 12 Dec 2023 07:55:00 +0000;Fri, 8 Dec 2023 11:00:00 +0000;Tue, 5 Dec 2023 08:00:00 +0000;Thu, 30 Nov 2023 21:48:42 +0000;Tue, 28 Nov 2023 08:00:00 +0000;Thu, 23 Nov 2023 08:00:00 +0000;Tue, 21 Nov 2023 08:00:00 +0000;Thu, 16 Nov 2023 22:50:22 +0000;Tue, 14 Nov 2023 08:00:00 +0000;Mon, 13 Nov 2023 08:00:00 +0000;Thu, 9 Nov 2023 06:00:10 +0000;Tue, 7 Nov 2023 08:00:00 +0000;Thu, 2 Nov 2023 19:55:29 +0000;Tue, 31 Oct 2023 07:00:00 +0000;Mon, 30 Oct 2023 07:00:00 +0000;Thu, 26 Oct 2023 21:07:46 +0000;Tue, 24 Oct 2023 06:57:10 +0000;Fri, 20 Oct 2023 08:42:10 +0000;Tue, 17 Oct 2023 07:00:00 +0000;Thu, 12 Oct 2023 21:09:03 +0000;Tue, 10 Oct 2023 07:00:00 +0000;Thu, 5 Oct 2023 23:31:25 +0000;Tue, 3 Oct 2023 07:00:00 +0000;Thu, 28 Sep 2023 07:52:30 +0000;Tue, 26 Sep 2023 07:00:00 +0000
+Sun, 18 Feb 2024 08:00:59 +0000;Sat, 17 Feb 2024 15:17:27 +0000;Fri, 16 Feb 2024 11:38:50 +0000;Thu, 15 Feb 2024 11:31:06 +0000;Wed, 14 Feb 2024 11:24:02 +0000;Tue, 13 Feb 2024 11:28:19 +0000;Mon, 12 Feb 2024 11:22:01 +0000;Sun, 11 Feb 2024 08:00:59 +0000;Sat, 10 Feb 2024 13:28:26 +0000;Fri, 09 Feb 2024 11:22:58 +0000;Thu, 08 Feb 2024 11:17:30 +0000;Wed, 07 Feb 2024 11:15:45 +0000;Tue, 06 Feb 2024 11:13:05 +0000;Mon, 05 Feb 2024 11:35:12 +0000;Sun, 04 Feb 2024 08:00:59 +0000;Sat, 03 Feb 2024 17:20:37 +0000;Fri, 02 Feb 2024 11:06:39 +0000;Thu, 01 Feb 2024 11:16:27 +0000;Wed, 31 Jan 2024 11:07:26 +0000;Tue, 30 Jan 2024 12:02:15 +0000;Mon, 29 Jan 2024 11:50:37 +0000;Sun, 28 Jan 2024 08:00:59 +0000;Sat, 27 Jan 2024 15:13:39 +0000;Fri, 26 Jan 2024 11:14:34 +0000;Thu, 25 Jan 2024 11:35:44 +0000;Wed, 24 Jan 2024 11:21:25 +0000;Tue, 23 Jan 2024 11:21:28 +0000;Mon, 22 Jan 2024 11:27:09 +0000;Sun, 21 Jan 2024 08:00:59 +0000;Sat, 20 Jan 2024 14:21:05 +0000;Fri, 19 Jan 2024 11:13:36 +0000;Thu, 18 Jan 2024 11:42:10 +0000;Wed, 17 Jan 2024 11:19:25 +0000;Tue, 16 Jan 2024 11:04:28 +0000;Mon, 15 Jan 2024 11:17:05 +0000;Sun, 14 Jan 2024 08:00:59 +0000;Sat, 13 Jan 2024 14:27:55 +0000;Fri, 12 Jan 2024 11:26:41 +0000;Thu, 11 Jan 2024 11:29:55 +0000;Wed, 10 Jan 2024 11:29:03 +0000;Tue, 09 Jan 2024 11:09:23 +0000;Mon, 08 Jan 2024 12:30:34 +0000;Sun, 07 Jan 2024 08:00:59 +0000;Sat, 06 Jan 2024 14:33:54 +0000;Fri, 05 Jan 2024 11:16:33 +0000;Thu, 04 Jan 2024 11:19:51 +0000;Wed, 03 Jan 2024 11:00:30 +0000;Tue, 02 Jan 2024 11:12:11 +0000;Mon, 01 Jan 2024 10:47:06 +0000;Sun, 31 Dec 2023 08:00:59 +0000
+Mon, 12 Feb 2024 08:01:00 -0000;Mon, 05 Feb 2024 08:01:00 -0000;Mon, 29 Jan 2024 08:01:00 -0000;Tue, 23 Jan 2024 13:00:00 -0000;Mon, 22 Jan 2024 08:01:00 -0000;Mon, 15 Jan 2024 08:01:00 -0000;Mon, 08 Jan 2024 08:01:00 -0000;Mon, 01 Jan 2024 08:01:00 -0000;Mon, 25 Dec 2023 08:01:00 -0000;Sun, 24 Dec 2023 08:01:00 -0000;Mon, 18 Dec 2023 08:01:00 -0000;Mon, 11 Dec 2023 08:01:00 -0000;Mon, 04 Dec 2023 08:01:00 -0000;Mon, 27 Nov 2023 08:01:00 -0000;Mon, 20 Nov 2023 08:01:00 -0000;Mon, 13 Nov 2023 08:01:00 -0000;Mon, 06 Nov 2023 08:01:00 -0000;Mon, 30 Oct 2023 07:01:00 -0000;Mon, 23 Oct 2023 07:01:00 -0000;Mon, 16 Oct 2023 07:01:00 -0000;Mon, 09 Oct 2023 07:01:00 -0000;Mon, 02 Oct 2023 07:01:00 -0000;Mon, 25 Sep 2023 07:01:00 -0000;Mon, 18 Sep 2023 07:01:00 -0000;Mon, 11 Sep 2023 07:01:00 -0000;Mon, 04 Sep 2023 07:01:00 -0000;Thu, 31 Aug 2023 07:01:00 -0000;Mon, 28 Aug 2023 07:01:00 -0000;Thu, 24 Aug 2023 07:01:00 -0000;Mon, 21 Aug 2023 07:01:00 -0000;Thu, 17 Aug 2023 07:01:00 -0000;Mon, 14 Aug 2023 07:01:00 -0000;Thu, 10 Aug 2023 07:01:00 -0000;Mon, 07 Aug 2023 07:01:00 -0000;Thu, 03 Aug 2023 07:01:00 -0000;Mon, 31 Jul 2023 07:01:00 -0000;Thu, 27 Jul 2023 07:01:00 -0000;Mon, 24 Jul 2023 07:01:00 -0000;Thu, 20 Jul 2023 07:01:00 -0000;Mon, 17 Jul 2023 07:01:00 -0000;Thu, 13 Jul 2023 07:01:00 -0000;Mon, 10 Jul 2023 07:01:00 -0000;Thu, 06 Jul 2023 07:01:00 -0000;Mon, 03 Jul 2023 07:01:00 -0000;Thu, 29 Jun 2023 07:01:00 -0000;Mon, 26 Jun 2023 07:01:00 -0000;Mon, 19 Jun 2023 07:01:00 -0000;Mon, 12 Jun 2023 07:01:00 -0000;Mon, 05 Jun 2023 07:01:00 -0000;Mon, 29 May 2023 07:01:00 -0000
+Thu, 15 Feb 2024 08:10:00 -0000;Wed, 14 Feb 2024 09:10:00 -0000;Mon, 12 Feb 2024 08:10:00 -0000;Thu, 08 Feb 2024 08:10:00 -0000;Wed, 07 Feb 2024 08:10:00 -0000;Mon, 05 Feb 2024 08:10:00 -0000;Thu, 01 Feb 2024 08:10:00 -0000;Wed, 31 Jan 2024 08:10:00 -0000;Mon, 29 Jan 2024 08:10:00 -0000;Thu, 25 Jan 2024 08:10:00 -0000;Wed, 24 Jan 2024 09:00:00 -0000;Mon, 22 Jan 2024 08:10:00 -0000;Thu, 18 Jan 2024 08:10:00 -0000;Wed, 17 Jan 2024 09:00:00 -0000;Mon, 15 Jan 2024 08:10:00 -0000;Thu, 11 Jan 2024 18:33:00 -0000;Wed, 10 Jan 2024 10:00:00 -0000;Mon, 08 Jan 2024 08:10:00 -0000;Thu, 04 Jan 2024 08:10:00 -0000;Mon, 01 Jan 2024 08:10:00 -0000;Mon, 25 Dec 2023 08:00:00 -0000;Thu, 21 Dec 2023 08:10:00 -0000;Wed, 20 Dec 2023 08:00:00 -0000;Mon, 18 Dec 2023 08:00:00 -0000;Thu, 14 Dec 2023 08:10:00 -0000;Mon, 11 Dec 2023 08:10:00 -0000;Thu, 07 Dec 2023 08:10:00 -0000;Wed, 06 Dec 2023 08:00:00 -0000;Mon, 04 Dec 2023 08:10:00 -0000;Thu, 30 Nov 2023 08:10:00 -0000;Mon, 27 Nov 2023 08:10:00 -0000;Wed, 22 Nov 2023 08:00:00 -0000;Mon, 20 Nov 2023 08:00:00 -0000;Thu, 16 Nov 2023 08:10:00 -0000;Wed, 15 Nov 2023 08:00:00 -0000;Mon, 13 Nov 2023 08:10:00 -0000;Thu, 09 Nov 2023 08:10:00 -0000;Wed, 08 Nov 2023 08:01:00 -0000;Mon, 06 Nov 2023 08:01:00 -0000;Thu, 02 Nov 2023 07:01:00 -0000;Wed, 01 Nov 2023 07:01:00 -0000;Sat, 28 Oct 2023 07:01:00 -0000;Thu, 26 Oct 2023 07:01:00 -0000;Wed, 25 Oct 2023 07:01:00 -0000;Mon, 23 Oct 2023 07:01:00 -0000;Thu, 19 Oct 2023 07:01:00 -0000;Wed, 18 Oct 2023 07:01:00 -0000;Mon, 16 Oct 2023 07:01:00 -0000;Thu, 12 Oct 2023 07:01:00 -0000;Wed, 11 Oct 2023 07:01:00 -0000
+Sat, 17 Feb 2024 10:00:00 +0000;Thu, 15 Feb 2024 10:00:00 +0000;Wed, 14 Feb 2024 10:00:00 +0000;Tue, 13 Feb 2024 10:00:00 +0000;Sat, 10 Feb 2024 10:00:00 +0000;Thu, 08 Feb 2024 14:04:39 +0000;Wed, 07 Feb 2024 10:00:00 +0000;Tue, 06 Feb 2024 10:00:00 +0000;Sat, 03 Feb 2024 10:00:00 +0000;Thu, 01 Feb 2024 16:16:12 +0000;Wed, 31 Jan 2024 10:00:00 +0000;Tue, 30 Jan 2024 13:30:44 +0000;Sat, 27 Jan 2024 10:00:00 +0000;Thu, 25 Jan 2024 15:22:59 +0000;Wed, 24 Jan 2024 10:00:00 +0000;Tue, 23 Jan 2024 10:00:00 +0000;Sat, 20 Jan 2024 10:00:00 +0000;Thu, 18 Jan 2024 10:00:00 +0000;Wed, 17 Jan 2024 14:11:56 +0000;Tue, 16 Jan 2024 16:01:35 +0000;Sat, 13 Jan 2024 10:00:00 +0000;Thu, 11 Jan 2024 10:00:00 +0000;Wed, 10 Jan 2024 10:00:00 +0000;Tue, 09 Jan 2024 10:00:00 +0000;Sat, 06 Jan 2024 10:00:00 +0000;Thu, 04 Jan 2024 10:00:00 +0000;Wed, 03 Jan 2024 10:00:00 +0000;Tue, 02 Jan 2024 10:00:00 +0000;Sat, 30 Dec 2023 10:00:00 +0000;Thu, 28 Dec 2023 10:00:00 +0000;Wed, 27 Dec 2023 10:00:00 +0000;Tue, 26 Dec 2023 10:00:00 +0000;Sat, 23 Dec 2023 10:00:00 +0000;Thu, 21 Dec 2023 10:00:00 +0000;Wed, 20 Dec 2023 10:00:00 +0000;Tue, 19 Dec 2023 10:00:00 +0000;Sat, 16 Dec 2023 10:00:00 +0000;Fri, 15 Dec 2023 15:31:05 +0000;Thu, 14 Dec 2023 10:00:00 +0000;Wed, 13 Dec 2023 10:00:00 +0000;Tue, 12 Dec 2023 10:00:00 +0000;Sat, 09 Dec 2023 10:00:00 +0000;Thu, 07 Dec 2023 10:00:00 +0000;Wed, 06 Dec 2023 14:19:34 +0000;Tue, 05 Dec 2023 10:00:00 +0000;Sat, 02 Dec 2023 10:00:00 +0000;Thu, 30 Nov 2023 11:00:00 +0000;Wed, 29 Nov 2023 10:00:00 +0000;Tue, 28 Nov 2023 11:00:00 +0000;Sat, 25 Nov 2023 10:00:00 +0000
+Fri, 16 Feb 2024 21:00:00 -0000;Tue, 13 Feb 2024 23:00:00 -0000;Mon, 12 Feb 2024 22:30:00 -0000;Fri, 09 Feb 2024 00:00:00 -0000;Wed, 07 Feb 2024 02:00:00 -0000;Sat, 03 Feb 2024 00:00:00 -0000;Fri, 02 Feb 2024 00:00:00 -0000;Wed, 31 Jan 2024 00:00:00 -0000;Mon, 29 Jan 2024 20:00:00 -0000;Sat, 27 Jan 2024 17:00:00 -0000;Sat, 27 Jan 2024 01:00:00 -0000;Fri, 26 Jan 2024 13:00:00 -0000;Wed, 24 Jan 2024 20:00:00 -0000;Tue, 23 Jan 2024 00:00:00 -0000;Sat, 20 Jan 2024 00:00:00 -0000;Thu, 18 Jan 2024 23:56:00 -0000;Tue, 16 Jan 2024 15:12:00 -0000;Sat, 13 Jan 2024 00:00:00 -0000;Fri, 12 Jan 2024 00:00:00 -0000;Tue, 09 Jan 2024 22:00:00 -0000;Sat, 06 Jan 2024 23:00:00 -0000;Sat, 06 Jan 2024 00:00:00 -0000;Thu, 04 Jan 2024 23:00:00 -0000;Sat, 30 Dec 2023 00:00:00 -0000;Thu, 28 Dec 2023 00:00:00 -0000;Thu, 21 Dec 2023 23:00:00 -0000;Wed, 20 Dec 2023 00:00:00 -0000;Tue, 19 Dec 2023 00:00:00 -0000;Fri, 15 Dec 2023 20:00:00 -0000;Thu, 14 Dec 2023 18:00:00 -0000;Wed, 13 Dec 2023 16:00:00 -0000;Tue, 12 Dec 2023 21:00:00 -0000;Mon, 11 Dec 2023 14:00:00 -0000;Tue, 05 Dec 2023 14:00:00 -0000
+
+Thu, 15 Feb 2024 08:00:00 +0000;Wed, 14 Feb 2024 08:00:00 +0000;Mon, 12 Feb 2024 08:00:00 +0000;Thu, 08 Feb 2024 08:00:00 +0000;Mon, 05 Feb 2024 08:00:00 +0000;Thu, 01 Feb 2024 08:00:00 +0000;Wed, 31 Jan 2024 08:00:00 +0000;Mon, 29 Jan 2024 08:00:00 +0000;Thu, 25 Jan 2024 08:00:00 +0000;Mon, 22 Jan 2024 08:00:00 +0000;Thu, 18 Jan 2024 08:00:00 +0000;Mon, 15 Jan 2024 08:00:00 +0000;Thu, 11 Jan 2024 08:00:00 +0000;Mon, 08 Jan 2024 08:00:00 +0000;Fri, 05 Jan 2024 01:01:59 +0000;Wed, 03 Jan 2024 08:00:00 +0000;Mon, 01 Jan 2024 08:00:00 +0000;Thu, 28 Dec 2023 08:00:00 +0000;Mon, 25 Dec 2023 08:00:00 +0000;Thu, 21 Dec 2023 08:00:00 +0000;Mon, 18 Dec 2023 08:00:00 +0000;Thu, 14 Dec 2023 08:00:00 +0000;Mon, 11 Dec 2023 08:00:00 +0000;Thu, 07 Dec 2023 08:00:00 +0000;Mon, 04 Dec 2023 10:00:00 +0000;Fri, 01 Dec 2023 08:00:00 +0000;Thu, 30 Nov 2023 08:00:00 +0000;Mon, 27 Nov 2023 10:00:00 +0000;Wed, 22 Nov 2023 22:53:32 +0000;Mon, 20 Nov 2023 08:00:00 +0000;Thu, 16 Nov 2023 08:00:00 +0000;Mon, 13 Nov 2023 08:00:00 +0000;Sun, 12 Nov 2023 08:00:00 +0000;Thu, 09 Nov 2023 08:00:00 +0000;Mon, 06 Nov 2023 08:00:00 +0000;Sun, 05 Nov 2023 07:00:00 +0000;Thu, 02 Nov 2023 07:00:00 +0000;Mon, 30 Oct 2023 07:00:00 +0000;Sun, 29 Oct 2023 07:00:00 +0000;Fri, 27 Oct 2023 18:54:42 +0000;Thu, 26 Oct 2023 07:00:00 +0000;Wed, 25 Oct 2023 07:00:00 +0000;Mon, 23 Oct 2023 07:00:00 +0000;Sun, 22 Oct 2023 07:00:00 +0000;Thu, 19 Oct 2023 07:00:00 +0000;Wed, 18 Oct 2023 07:00:00 +0000;Mon, 16 Oct 2023 07:00:00 +0000;Thu, 12 Oct 2023 07:00:00 +0000;Wed, 11 Oct 2023 07:00:00 +0000;Mon, 09 Oct 2023 07:00:00 +0000
+Sun, 18 Feb 2024 03:15:00 -0500;Sat, 17 Feb 2024 03:15:00 -0500;Fri, 16 Feb 2024 03:15:00 -0500;Thu, 15 Feb 2024 03:15:00 -0500;Wed, 14 Feb 2024 03:15:00 -0500;Tue, 13 Feb 2024 03:15:00 -0500;Mon, 12 Feb 2024 03:15:00 -0500;Sun, 11 Feb 2024 03:15:00 -0500;Sat, 10 Feb 2024 03:15:00 -0500;Fri, 09 Feb 2024 03:15:00 -0500;Thu, 08 Feb 2024 03:15:00 -0500;Wed, 07 Feb 2024 03:15:00 -0500;Tue, 06 Feb 2024 03:15:00 -0500;Mon, 05 Feb 2024 03:15:00 -0500;Sun, 04 Feb 2024 03:15:00 -0500;Sat, 03 Feb 2024 03:15:00 -0500;Fri, 02 Feb 2024 03:15:00 -0500;Thu, 01 Feb 2024 03:15:00 -0500;Wed, 31 Jan 2024 03:15:00 -0500;Tue, 30 Jan 2024 03:15:00 -0500;Mon, 29 Jan 2024 03:15:00 -0500;Sun, 28 Jan 2024 03:15:00 -0500;Sat, 27 Jan 2024 03:15:00 -0500;Sat, 27 Jan 2024 03:15:00 -0500;Fri, 26 Jan 2024 03:15:00 -0500;Thu, 25 Jan 2024 03:15:00 -0500;Wed, 24 Jan 2024 03:15:00 -0500;Tue, 23 Jan 2024 03:15:00 -0500;Mon, 22 Jan 2024 03:15:00 -0500;Sun, 21 Jan 2024 03:15:00 -0500;Sat, 20 Jan 2024 03:15:00 -0500;Fri, 19 Jan 2024 03:15:00 -0500;Thu, 18 Jan 2024 03:15:00 -0500;Wed, 17 Jan 2024 03:15:00 -0500;Tue, 16 Jan 2024 03:15:00 -0500;Mon, 15 Jan 2024 03:15:00 -0500;Sun, 14 Jan 2024 03:15:00 -0500;Sat, 13 Jan 2024 03:15:00 -0500;Fri, 12 Jan 2024 03:15:00 -0500;Thu, 11 Jan 2024 03:15:00 -0500;Wed, 10 Jan 2024 03:15:00 -0500;Tue, 09 Jan 2024 03:15:00 -0500;Mon, 08 Jan 2024 03:15:00 -0500;Sun, 07 Jan 2024 03:15:00 -0500;Sat, 06 Jan 2024 03:15:00 -0500;Sat, 06 Jan 2024 03:15:00 -0500;Fri, 05 Jan 2024 03:15:00 -0500;Thu, 04 Jan 2024 03:15:00 -0500;Wed, 03 Jan 2024 03:15:00 -0500;Tue, 02 Jan 2024 03:15:00 -0500
+Sun, 18 Feb 2024 11:00:00 +0000;Thu, 15 Feb 2024 08:00:00 +0000;Wed, 14 Feb 2024 08:00:00 +0000;Tue, 13 Feb 2024 08:00:00 +0000;Mon, 12 Feb 2024 08:00:00 +0000;Sun, 11 Feb 2024 08:00:00 +0000;Thu, 08 Feb 2024 08:00:00 +0000;Wed, 07 Feb 2024 08:00:00 +0000;Tue, 06 Feb 2024 08:00:00 +0000;Mon, 05 Feb 2024 08:00:00 +0000;Sun, 04 Feb 2024 08:00:00 +0000;Thu, 01 Feb 2024 08:00:00 +0000;Wed, 31 Jan 2024 08:00:00 +0000;Tue, 30 Jan 2024 08:00:00 +0000;Mon, 29 Jan 2024 08:00:00 +0000;Sun, 28 Jan 2024 08:00:00 +0000;Thu, 25 Jan 2024 08:00:00 +0000;Wed, 24 Jan 2024 08:00:00 +0000;Tue, 23 Jan 2024 08:00:00 +0000;Mon, 22 Jan 2024 08:00:00 +0000;Sun, 21 Jan 2024 08:00:00 +0000;Thu, 18 Jan 2024 08:00:00 +0000;Wed, 17 Jan 2024 08:00:00 +0000;Tue, 16 Jan 2024 08:00:00 +0000;Mon, 15 Jan 2024 08:00:00 +0000;Sun, 14 Jan 2024 08:00:00 +0000;Thu, 11 Jan 2024 08:00:00 +0000;Wed, 10 Jan 2024 08:00:00 +0000;Tue, 09 Jan 2024 08:00:00 +0000;Mon, 08 Jan 2024 08:00:00 +0000;Sun, 07 Jan 2024 08:00:00 +0000;Thu, 04 Jan 2024 08:00:00 +0000;Wed, 03 Jan 2024 08:00:00 +0000;Tue, 02 Jan 2024 08:00:00 +0000;Mon, 01 Jan 2024 08:00:00 +0000;Sun, 31 Dec 2023 08:00:00 +0000;Sat, 30 Dec 2023 14:00:00 +0000;Fri, 29 Dec 2023 14:00:00 +0000;Thu, 28 Dec 2023 14:00:00 +0000;Wed, 27 Dec 2023 08:00:00 +0000;Tue, 26 Dec 2023 14:00:00 +0000;Mon, 25 Dec 2023 14:00:00 +0000;Sun, 24 Dec 2023 14:00:00 +0000;Sat, 23 Dec 2023 14:00:00 +0000;Fri, 22 Dec 2023 14:00:00 +0000;Thu, 21 Dec 2023 14:00:00 +0000;Wed, 20 Dec 2023 14:00:00 +0000;Tue, 19 Dec 2023 14:00:00 +0000;Mon, 18 Dec 2023 14:00:00 +0000;Sun, 17 Dec 2023 14:00:00 +0000
+Sat, 17 Feb 2024 17:13:25 -0000;Wed, 14 Feb 2024 08:00:00 -0000;Tue, 13 Feb 2024 08:00:00 -0000;Sat, 10 Feb 2024 17:26:04 -0000;Wed, 07 Feb 2024 08:00:00 -0000;Tue, 06 Feb 2024 08:00:00 -0000;Sat, 03 Feb 2024 17:41:00 -0000;Wed, 31 Jan 2024 08:00:00 -0000;Tue, 30 Jan 2024 08:00:00 -0000;Sat, 27 Jan 2024 19:19:20 -0000;Wed, 24 Jan 2024 08:00:00 -0000;Tue, 23 Jan 2024 08:00:00 -0000;Sat, 20 Jan 2024 19:44:42 -0000;Wed, 17 Jan 2024 08:00:00 -0000;Sat, 13 Jan 2024 18:28:35 -0000;Wed, 10 Jan 2024 08:00:00 -0000;Sat, 06 Jan 2024 16:43:45 -0000;Wed, 03 Jan 2024 08:00:00 -0000;Sat, 30 Dec 2023 17:06:00 -0000;Wed, 27 Dec 2023 12:44:00 -0000;Wed, 27 Dec 2023 08:00:00 -0000;Wed, 20 Dec 2023 08:00:00 -0000;Sat, 16 Dec 2023 17:39:54 -0000;Wed, 13 Dec 2023 08:00:00 -0000;Sat, 09 Dec 2023 18:57:17 -0000;Wed, 06 Dec 2023 08:00:00 -0000;Wed, 29 Nov 2023 08:00:00 -0000;Wed, 22 Nov 2023 08:00:00 -0000;Sat, 18 Nov 2023 17:34:30 -0000;Wed, 15 Nov 2023 08:00:00 -0000
+Thu, 15 Feb 2024 05:05:00 +0000;Mon, 12 Feb 2024 05:05:00 +0000;Thu, 8 Feb 2024 05:05:00 +0000;Mon, 5 Feb 2024 05:05:00 +0000;Thu, 1 Feb 2024 05:05:00 +0000;Mon, 29 Jan 2024 05:05:00 +0000;Thu, 25 Jan 2024 05:05:00 +0000;Mon, 22 Jan 2024 05:05:00 +0000;Thu, 18 Jan 2024 05:05:00 +0000;Mon, 15 Jan 2024 05:05:00 +0000;Thu, 11 Jan 2024 05:05:00 +0000;Mon, 8 Jan 2024 05:05:00 +0000;Thu, 4 Jan 2024 05:05:00 +0000;Mon, 1 Jan 2024 05:05:00 +0000;Thu, 28 Dec 2023 05:05:00 +0000;Mon, 25 Dec 2023 05:05:00 +0000;Thu, 21 Dec 2023 05:05:00 +0000;Mon, 18 Dec 2023 05:10:00 +0000;Mon, 18 Dec 2023 05:05:00 +0000;Thu, 14 Dec 2023 05:05:00 +0000;Mon, 11 Dec 2023 05:05:00 +0000;Thu, 7 Dec 2023 05:05:00 +0000;Mon, 4 Dec 2023 05:05:00 +0000;Thu, 30 Nov 2023 05:05:00 +0000;Mon, 27 Nov 2023 05:05:00 +0000;Thu, 23 Nov 2023 05:05:00 +0000;Mon, 20 Nov 2023 05:05:00 +0000;Thu, 16 Nov 2023 05:05:00 +0000;Mon, 13 Nov 2023 05:05:00 +0000;Thu, 9 Nov 2023 05:05:00 +0000;Mon, 6 Nov 2023 05:05:00 +0000;Thu, 2 Nov 2023 04:05:00 +0000;Mon, 30 Oct 2023 04:05:00 +0000;Thu, 26 Oct 2023 04:05:00 +0000;Mon, 23 Oct 2023 04:05:00 +0000;Thu, 19 Oct 2023 04:05:00 +0000;Mon, 16 Oct 2023 04:05:00 +0000;Thu, 12 Oct 2023 04:05:00 +0000;Tue, 10 Oct 2023 20:59:11 +0000;Mon, 9 Oct 2023 04:05:00 +0000;Thu, 5 Oct 2023 04:05:00 +0000;Mon, 2 Oct 2023 04:05:00 +0000;Thu, 28 Sep 2023 04:05:00 +0000;Mon, 25 Sep 2023 04:05:00 +0000;Thu, 21 Sep 2023 04:05:00 +0000;Mon, 18 Sep 2023 04:05:00 +0000;Thu, 14 Sep 2023 04:05:00 +0000;Mon, 11 Sep 2023 04:05:00 +0000;Thu, 7 Sep 2023 04:05:00 +0000;Mon, 4 Sep 2023 04:05:00 +0000
+Fri, 16 Feb 2024 05:00:00 -0000;Thu, 15 Feb 2024 05:00:00 -0000;Wed, 14 Feb 2024 05:00:00 -0000;Tue, 13 Feb 2024 05:00:00 -0000;Fri, 09 Feb 2024 05:00:00 -0000;Thu, 08 Feb 2024 05:00:00 -0000;Wed, 07 Feb 2024 05:00:00 -0000;Tue, 06 Feb 2024 05:00:00 -0000;Fri, 02 Feb 2024 05:00:00 -0000;Thu, 01 Feb 2024 05:00:00 -0000;Wed, 31 Jan 2024 05:00:00 -0000;Tue, 30 Jan 2024 05:00:00 -0000;Fri, 26 Jan 2024 05:00:00 -0000;Thu, 25 Jan 2024 05:00:00 -0000;Wed, 24 Jan 2024 05:00:00 -0000;Tue, 23 Jan 2024 05:00:00 -0000;Fri, 19 Jan 2024 05:00:00 -0000;Thu, 18 Jan 2024 05:00:00 -0000;Wed, 17 Jan 2024 05:00:00 -0000;Tue, 16 Jan 2024 05:00:00 -0000;Fri, 12 Jan 2024 05:05:00 -0000;Thu, 11 Jan 2024 05:05:00 -0000;Wed, 10 Jan 2024 05:05:00 -0000;Tue, 09 Jan 2024 05:05:00 -0000;Fri, 05 Jan 2024 05:05:00 -0000;Thu, 04 Jan 2024 05:05:00 -0000;Wed, 03 Jan 2024 05:05:00 -0000;Tue, 02 Jan 2024 05:05:00 -0000;Fri, 29 Dec 2023 05:05:00 -0000;Thu, 28 Dec 2023 05:05:00 -0000;Wed, 27 Dec 2023 05:05:00 -0000;Tue, 26 Dec 2023 05:05:00 -0000;Fri, 22 Dec 2023 05:05:00 -0000;Thu, 21 Dec 2023 05:05:00 -0000;Wed, 20 Dec 2023 05:05:00 -0000;Tue, 19 Dec 2023 05:05:00 -0000;Fri, 15 Dec 2023 05:05:00 -0000;Thu, 14 Dec 2023 05:05:00 -0000;Wed, 13 Dec 2023 05:05:00 -0000;Tue, 12 Dec 2023 05:05:00 -0000;Fri, 08 Dec 2023 05:05:00 -0000;Thu, 07 Dec 2023 05:05:00 -0000;Wed, 06 Dec 2023 05:05:00 -0000;Tue, 05 Dec 2023 05:05:00 -0000;Fri, 01 Dec 2023 05:05:00 -0000;Thu, 30 Nov 2023 05:05:00 -0000;Wed, 29 Nov 2023 13:50:00 -0000;Tue, 28 Nov 2023 05:05:00 -0000;Fri, 24 Nov 2023 05:05:00 -0000;Thu, 23 Nov 2023 05:05:00 -0000
+Thu, 15 Feb 2024 08:01:00 -0000;Mon, 12 Feb 2024 08:01:00 -0000;Thu, 08 Feb 2024 08:01:00 -0000;Mon, 05 Feb 2024 08:01:00 -0000;Thu, 01 Feb 2024 08:01:00 -0000;Mon, 29 Jan 2024 08:01:00 -0000;Thu, 25 Jan 2024 08:01:00 -0000;Mon, 22 Jan 2024 08:01:00 -0000;Thu, 18 Jan 2024 08:01:00 -0000;Mon, 15 Jan 2024 08:01:00 -0000;Thu, 11 Jan 2024 08:01:00 -0000;Mon, 08 Jan 2024 08:01:00 -0000;Thu, 04 Jan 2024 08:01:00 -0000;Mon, 01 Jan 2024 08:01:00 -0000;Thu, 21 Dec 2023 08:01:00 -0000;Mon, 18 Dec 2023 08:01:00 -0000;Thu, 14 Dec 2023 08:01:00 -0000;Mon, 11 Dec 2023 08:01:00 -0000;Thu, 07 Dec 2023 08:01:00 -0000;Mon, 04 Dec 2023 08:01:00 -0000;Thu, 30 Nov 2023 08:01:00 -0000;Mon, 27 Nov 2023 08:01:00 -0000;Thu, 23 Nov 2023 08:01:00 -0000;Mon, 20 Nov 2023 08:01:00 -0000;Thu, 16 Nov 2023 08:01:00 -0000;Mon, 13 Nov 2023 08:01:00 -0000;Thu, 09 Nov 2023 08:01:00 -0000;Mon, 06 Nov 2023 08:01:00 -0000;Thu, 02 Nov 2023 07:01:00 -0000;Mon, 30 Oct 2023 07:01:00 -0000;Thu, 26 Oct 2023 07:01:00 -0000;Mon, 23 Oct 2023 07:01:00 -0000;Thu, 19 Oct 2023 07:01:00 -0000;Mon, 16 Oct 2023 07:01:00 -0000;Thu, 12 Oct 2023 07:01:00 -0000;Mon, 09 Oct 2023 07:01:00 -0000;Thu, 05 Oct 2023 07:01:00 -0000;Mon, 02 Oct 2023 07:01:00 -0000;Thu, 28 Sep 2023 07:01:00 -0000;Mon, 25 Sep 2023 07:01:00 -0000;Thu, 21 Sep 2023 07:01:00 -0000;Mon, 18 Sep 2023 07:01:00 -0000;Fri, 15 Sep 2023 07:01:00 -0000;Thu, 14 Sep 2023 07:01:00 -0000;Mon, 11 Sep 2023 07:01:00 -0000;Thu, 07 Sep 2023 07:01:00 -0000;Mon, 04 Sep 2023 07:01:00 -0000;Thu, 31 Aug 2023 07:01:00 -0000;Mon, 28 Aug 2023 07:01:00 -0000;Thu, 24 Aug 2023 07:01:00 -0000
+Fri, 16 Feb 2024 00:53:00 -0000;Wed, 14 Feb 2024 08:14:00 -0000;Tue, 06 Feb 2024 08:00:00 -0000;Tue, 30 Jan 2024 09:07:00 -0000;Tue, 23 Jan 2024 08:00:00 -0000;Tue, 16 Jan 2024 10:52:00 -0000;Tue, 09 Jan 2024 08:00:00 -0000;Tue, 02 Jan 2024 08:35:00 -0000;Wed, 20 Dec 2023 19:10:00 -0000;Tue, 12 Dec 2023 08:00:00 -0000;Tue, 05 Dec 2023 08:00:00 -0000;Tue, 28 Nov 2023 08:00:00 -0000;Tue, 21 Nov 2023 08:00:00 -0000;Tue, 14 Nov 2023 08:00:00 -0000;Tue, 07 Nov 2023 10:22:00 -0000;Tue, 31 Oct 2023 08:00:00 -0000;Tue, 24 Oct 2023 07:00:00 -0000;Tue, 10 Oct 2023 07:00:00 -0000;Tue, 03 Oct 2023 08:00:00 -0000;Mon, 25 Sep 2023 19:05:10 -0000;Tue, 19 Sep 2023 11:25:00 -0000;Tue, 12 Sep 2023 07:00:00 -0000;Wed, 06 Sep 2023 08:15:46 -0000;Tue, 29 Aug 2023 07:31:00 -0000;Tue, 22 Aug 2023 07:30:00 -0000;Tue, 15 Aug 2023 07:00:00 -0000;Tue, 08 Aug 2023 07:00:00 -0000;Tue, 01 Aug 2023 07:00:00 -0000;Tue, 25 Jul 2023 07:00:00 -0000;Fri, 21 Jul 2023 07:00:00 -0000;Tue, 18 Jul 2023 07:00:00 -0000;Tue, 11 Jul 2023 10:00:00 -0000;Wed, 05 Jul 2023 07:00:00 -0000;Tue, 27 Jun 2023 07:00:00 -0000;Tue, 20 Jun 2023 07:00:00 -0000;Wed, 14 Jun 2023 05:00:00 -0000;Tue, 06 Jun 2023 08:00:00 -0000;Tue, 30 May 2023 07:00:00 -0000;Tue, 23 May 2023 07:00:00 -0000;Tue, 16 May 2023 05:00:00 -0000;Tue, 09 May 2023 07:00:00 -0000;Tue, 02 May 2023 07:00:00 -0000;Tue, 25 Apr 2023 07:00:00 -0000;Tue, 18 Apr 2023 07:00:00 -0000;Tue, 11 Apr 2023 07:00:00 -0000;Wed, 05 Apr 2023 01:30:00 -0000;Tue, 28 Mar 2023 07:00:00 -0000;Tue, 21 Mar 2023 08:00:00 -0000;Tue, 14 Mar 2023 07:00:00 -0000;Thu, 09 Mar 2023 08:00:00 -0000
+Fri, 16 Feb 2024 10:30:00 +0000;Fri, 09 Feb 2024 10:30:00 +0000;Fri, 02 Feb 2024 10:30:00 +0000;Fri, 26 Jan 2024 10:30:00 +0000;Fri, 19 Jan 2024 10:30:00 +0000;Fri, 12 Jan 2024 10:30:00 +0000;Fri, 05 Jan 2024 10:30:00 +0000;Fri, 29 Dec 2023 11:00:00 +0000;Fri, 22 Dec 2023 11:00:00 +0000;Fri, 15 Dec 2023 11:00:00 +0000;Fri, 08 Dec 2023 11:00:00 +0000;Fri, 01 Dec 2023 10:30:00 +0000;Fri, 24 Nov 2023 11:00:00 +0000;Fri, 17 Nov 2023 11:00:00 +0000;Fri, 10 Nov 2023 10:30:00 +0000;Fri, 03 Nov 2023 09:30:00 +0000;Fri, 27 Oct 2023 09:30:00 +0000;Fri, 20 Oct 2023 09:30:00 +0000;Fri, 13 Oct 2023 09:30:00 +0000;Fri, 06 Oct 2023 09:30:00 +0000;Fri, 29 Sep 2023 09:30:00 +0000;Fri, 22 Sep 2023 09:30:00 +0000;Fri, 15 Sep 2023 09:30:00 +0000;Fri, 08 Sep 2023 09:30:00 +0000;Fri, 01 Sep 2023 09:30:00 +0000;Fri, 25 Aug 2023 09:30:00 +0000;Fri, 18 Aug 2023 09:30:00 +0000;Fri, 11 Aug 2023 09:30:00 +0000;Fri, 04 Aug 2023 09:00:00 +0000;Fri, 17 Feb 2023 16:40:40 +0000
+Sun, 18 Feb 2024 08:00:00 -0000;Sat, 17 Feb 2024 08:00:00 -0000;Fri, 16 Feb 2024 08:00:00 -0000;Thu, 15 Feb 2024 08:00:00 -0000;Wed, 14 Feb 2024 08:00:00 -0000;Tue, 13 Feb 2024 08:00:00 -0000;Mon, 12 Feb 2024 08:00:00 -0000;Sun, 11 Feb 2024 08:10:00 -0000;Sat, 10 Feb 2024 08:00:00 -0000;Fri, 09 Feb 2024 08:00:00 -0000;Thu, 08 Feb 2024 08:00:00 -0000;Wed, 07 Feb 2024 08:00:00 -0000;Tue, 06 Feb 2024 08:00:00 -0000;Mon, 05 Feb 2024 08:00:00 -0000;Fri, 02 Feb 2024 16:47:00 -0000;Thu, 01 Feb 2024 08:09:00 -0000;Wed, 31 Jan 2024 08:00:00 -0000;Tue, 30 Jan 2024 08:00:00 -0000;Mon, 29 Jan 2024 14:28:00 -0000;Fri, 26 Jan 2024 08:00:00 -0000;Thu, 25 Jan 2024 08:00:00 -0000;Wed, 24 Jan 2024 08:00:00 -0000;Tue, 23 Jan 2024 08:00:00 -0000;Mon, 22 Jan 2024 08:00:00 -0000;Sun, 21 Jan 2024 09:42:00 -0000;Sat, 20 Jan 2024 08:00:00 -0000;Fri, 19 Jan 2024 08:00:00 -0000;Thu, 18 Jan 2024 08:00:00 -0000;Wed, 17 Jan 2024 08:00:00 -0000;Tue, 16 Jan 2024 08:00:00 -0000;Mon, 15 Jan 2024 08:00:00 -0000;Sun, 14 Jan 2024 08:00:00 -0000;Sat, 13 Jan 2024 08:00:00 -0000;Fri, 12 Jan 2024 08:00:00 -0000;Thu, 11 Jan 2024 08:00:00 -0000;Wed, 10 Jan 2024 08:00:00 -0000;Tue, 09 Jan 2024 08:00:00 -0000;Mon, 08 Jan 2024 08:00:00 -0000;Fri, 05 Jan 2024 08:00:00 -0000;Thu, 04 Jan 2024 16:27:00 -0000;Wed, 03 Jan 2024 08:00:00 -0000;Tue, 02 Jan 2024 16:09:00 -0000;Mon, 01 Jan 2024 08:00:00 -0000;Fri, 29 Dec 2023 08:00:00 -0000;Thu, 28 Dec 2023 08:00:00 -0000;Wed, 27 Dec 2023 08:00:00 -0000;Tue, 26 Dec 2023 08:00:00 -0000;Mon, 25 Dec 2023 08:00:00 -0000;Sat, 23 Dec 2023 08:00:00 -0000;Fri, 22 Dec 2023 08:00:00 -0000
+Fri, 16 Feb 2024 22:51:00 -0000;Thu, 15 Feb 2024 22:56:00 -0000;Wed, 14 Feb 2024 22:57:00 -0000;Tue, 13 Feb 2024 22:56:00 -0000;Mon, 12 Feb 2024 23:00:00 -0000;Fri, 09 Feb 2024 22:56:00 -0000;Thu, 08 Feb 2024 23:30:00 -0000;Wed, 07 Feb 2024 23:09:00 -0000;Tue, 06 Feb 2024 22:59:00 -0000;Mon, 05 Feb 2024 22:56:00 -0000;Fri, 02 Feb 2024 22:58:00 -0000;Thu, 01 Feb 2024 22:54:00 -0000;Wed, 31 Jan 2024 22:58:00 -0000;Tue, 30 Jan 2024 22:57:00 -0000;Mon, 29 Jan 2024 22:56:00 -0000;Fri, 26 Jan 2024 22:53:00 -0000;Thu, 25 Jan 2024 23:00:00 -0000;Wed, 24 Jan 2024 22:58:00 -0000;Tue, 23 Jan 2024 23:06:00 -0000;Mon, 22 Jan 2024 22:56:00 -0000;Sat, 20 Jan 2024 00:00:00 -0000;Fri, 19 Jan 2024 22:55:00 -0000;Thu, 18 Jan 2024 22:58:00 -0000;Wed, 17 Jan 2024 22:52:00 -0000;Tue, 16 Jan 2024 23:01:00 -0000;Mon, 15 Jan 2024 23:04:00 -0000;Fri, 12 Jan 2024 23:04:00 -0000;Thu, 11 Jan 2024 22:53:00 -0000;Thu, 11 Jan 2024 00:01:00 -0000;Tue, 09 Jan 2024 22:57:00 -0000;Mon, 08 Jan 2024 23:08:00 -0000;Fri, 05 Jan 2024 22:55:00 -0000;Thu, 04 Jan 2024 23:15:00 -0000;Wed, 03 Jan 2024 23:03:00 -0000;Tue, 02 Jan 2024 23:07:00 -0000;Mon, 01 Jan 2024 23:35:00 -0000;Fri, 29 Dec 2023 23:07:00 -0000;Thu, 28 Dec 2023 23:14:00 -0000;Wed, 27 Dec 2023 23:02:00 -0000;Tue, 26 Dec 2023 22:57:00 -0000;Mon, 25 Dec 2023 13:00:00 -0000;Fri, 22 Dec 2023 22:57:00 -0000;Thu, 21 Dec 2023 23:02:00 -0000;Wed, 20 Dec 2023 23:03:00 -0000;Tue, 19 Dec 2023 23:01:00 -0000;Mon, 18 Dec 2023 23:06:00 -0000;Fri, 15 Dec 2023 23:05:00 -0000;Thu, 14 Dec 2023 23:04:00 -0000;Wed, 13 Dec 2023 23:00:00 -0000;Tue, 12 Dec 2023 23:00:00 -0000
+Fri, 16 Feb 2024 08:05:00 +0000;Fri, 16 Feb 2024 08:00:00 +0000;Tue, 30 Jan 2024 08:00:00 +0000
+Thu, 15 Feb 2024 08:00:00 +0000;Thu, 8 Feb 2024 08:05:00 +0000;Thu, 8 Feb 2024 08:00:00 +0000;Thu, 1 Feb 2024 08:00:00 +0000;Thu, 25 Jan 2024 08:00:00 +0000;Thu, 18 Jan 2024 08:00:00 +0000;Thu, 11 Jan 2024 08:00:00 +0000;Thu, 4 Jan 2024 08:00:00 +0000;Mon, 25 Sep 2023 07:05:00 +0000;Sat, 23 Sep 2023 20:59:07 +0000;Mon, 18 Sep 2023 07:30:00 +0000;Mon, 11 Sep 2023 07:30:00 +0000;Mon, 28 Aug 2023 07:30:00 +0000;Mon, 21 Aug 2023 07:30:00 +0000;Mon, 14 Aug 2023 07:30:00 +0000;Mon, 7 Aug 2023 07:30:00 +0000;Mon, 31 Jul 2023 07:30:00 +0000;Mon, 10 Jul 2023 07:30:00 +0000;Mon, 3 Jul 2023 07:30:00 +0000;Mon, 26 Jun 2023 07:30:00 +0000;Mon, 19 Jun 2023 07:30:00 +0000;Mon, 12 Jun 2023 07:30:00 +0000;Mon, 5 Jun 2023 07:30:00 +0000;Mon, 29 May 2023 07:30:00 +0000;Mon, 22 May 2023 07:30:00 +0000;Mon, 15 May 2023 07:30:00 +0000;Mon, 8 May 2023 07:30:00 +0000;Mon, 1 May 2023 07:30:00 +0000;Mon, 24 Apr 2023 07:30:00 +0000;Mon, 17 Apr 2023 07:30:00 +0000;Mon, 10 Apr 2023 07:30:00 +0000;Tue, 4 Apr 2023 06:30:00 +0000;Mon, 3 Apr 2023 07:30:00 +0000;Mon, 27 Mar 2023 07:30:00 +0000;Mon, 20 Mar 2023 07:30:00 +0000;Mon, 13 Mar 2023 07:30:00 +0000;Mon, 6 Mar 2023 07:31:00 +0000;Mon, 6 Mar 2023 07:30:00 +0000;Mon, 27 Feb 2023 07:30:00 +0000;Mon, 20 Feb 2023 07:30:00 +0000;Mon, 13 Feb 2023 07:30:00 +0000;Mon, 6 Feb 2023 07:30:00 +0000;Mon, 30 Jan 2023 07:30:00 +0000;Mon, 16 Jan 2023 07:30:00 +0000;Mon, 9 Jan 2023 07:30:00 +0000;Mon, 2 Jan 2023 07:30:00 +0000;Mon, 26 Dec 2022 07:30:00 +0000;Mon, 12 Dec 2022 07:30:00 +0000;Mon, 28 Nov 2022 07:30:00 +0000;Mon, 21 Nov 2022 07:30:00 +0000
+Thu, 15 Feb 2024 08:01:00 -0000;Tue, 13 Feb 2024 08:01:00 -0000;Mon, 12 Feb 2024 08:01:00 -0000;Thu, 08 Feb 2024 08:01:00 -0000;Tue, 06 Feb 2024 08:01:00 -0000;Mon, 05 Feb 2024 08:01:00 -0000;Thu, 01 Feb 2024 08:01:00 -0000;Tue, 30 Jan 2024 08:01:00 -0000;Mon, 29 Jan 2024 08:01:00 -0000;Thu, 25 Jan 2024 08:01:00 -0000;Tue, 23 Jan 2024 08:01:00 -0000;Mon, 22 Jan 2024 08:01:00 -0000;Thu, 18 Jan 2024 08:01:00 -0000;Tue, 16 Jan 2024 08:01:00 -0000;Mon, 15 Jan 2024 08:01:00 -0000;Thu, 11 Jan 2024 08:01:00 -0000;Tue, 09 Jan 2024 08:01:00 -0000;Mon, 08 Jan 2024 08:01:00 -0000;Thu, 04 Jan 2024 08:01:00 -0000;Tue, 02 Jan 2024 08:01:00 -0000;Sun, 31 Dec 2023 16:59:02 -0000;Thu, 28 Dec 2023 08:01:00 -0000;Tue, 26 Dec 2023 08:01:00 -0000;Sun, 24 Dec 2023 17:40:25 -0000;Thu, 21 Dec 2023 08:01:00 -0000;Tue, 19 Dec 2023 08:01:00 -0000;Sun, 17 Dec 2023 16:58:44 -0000;Thu, 14 Dec 2023 08:01:00 -0000;Tue, 12 Dec 2023 08:01:00 -0000;Sun, 10 Dec 2023 16:53:28 -0000;Thu, 07 Dec 2023 08:01:00 -0000;Tue, 05 Dec 2023 08:01:00 -0000;Sun, 03 Dec 2023 16:56:40 -0000;Thu, 30 Nov 2023 08:01:00 -0000;Tue, 28 Nov 2023 08:01:00 -0000;Sun, 26 Nov 2023 19:03:55 -0000;Thu, 23 Nov 2023 08:01:00 -0000;Tue, 21 Nov 2023 08:01:00 -0000;Sun, 19 Nov 2023 18:18:39 -0000;Thu, 16 Nov 2023 08:01:00 -0000;Tue, 14 Nov 2023 08:01:00 -0000;Sun, 12 Nov 2023 16:54:19 -0000;Thu, 09 Nov 2023 08:01:00 -0000;Tue, 07 Nov 2023 08:01:00 -0000;Sun, 05 Nov 2023 17:00:00 -0000;Thu, 02 Nov 2023 07:01:00 -0000;Tue, 31 Oct 2023 07:01:00 -0000;Sun, 29 Oct 2023 23:11:12 -0000;Thu, 26 Oct 2023 04:00:00 -0000;Tue, 24 Oct 2023 07:01:00 -0000
+Fri, 16 Feb 2024 10:00:00 +0000;Tue, 13 Feb 2024 10:00:00 +0000;Fri, 9 Feb 2024 10:00:00 +0000;Tue, 6 Feb 2024 10:00:00 +0000;Thu, 1 Feb 2024 10:00:00 +0000;Thu, 25 Jan 2024 10:00:00 +0000;Fri, 19 Jan 2024 10:00:00 +0000;Tue, 16 Jan 2024 10:00:00 +0000;Fri, 12 Jan 2024 10:00:00 +0000;Tue, 9 Jan 2024 10:00:00 +0000;Fri, 5 Jan 2024 10:00:00 +0000;Tue, 26 Dec 2023 10:00:00 +0000;Fri, 22 Dec 2023 10:00:00 +0000;Tue, 19 Dec 2023 10:00:00 +0000;Tue, 12 Dec 2023 10:00:00 +0000;Fri, 8 Dec 2023 10:00:00 +0000;Tue, 5 Dec 2023 10:00:00 +0000;Fri, 1 Dec 2023 10:00:00 +0000;Tue, 28 Nov 2023 10:00:00 +0000;Tue, 21 Nov 2023 10:00:00 +0000;Fri, 17 Nov 2023 10:00:00 +0000;Tue, 14 Nov 2023 10:00:00 +0000;Fri, 10 Nov 2023 10:00:00 +0000;Tue, 7 Nov 2023 10:00:00 +0000;Fri, 3 Nov 2023 09:00:00 +0000;Tue, 31 Oct 2023 09:00:00 +0000;Fri, 27 Oct 2023 09:00:00 +0000;Tue, 24 Oct 2023 09:00:00 +0000;Wed, 18 Oct 2023 09:00:00 +0000;Tue, 10 Oct 2023 09:00:00 +0000;Tue, 3 Oct 2023 09:00:00 +0000;Tue, 26 Sep 2023 09:00:00 +0000;Tue, 19 Sep 2023 09:00:00 +0000;Tue, 12 Sep 2023 09:00:00 +0000;Tue, 5 Sep 2023 09:00:00 +0000;Tue, 29 Aug 2023 09:00:00 +0000;Tue, 22 Aug 2023 09:00:00 +0000;Tue, 15 Aug 2023 09:00:00 +0000;Tue, 8 Aug 2023 09:00:00 +0000;Tue, 1 Aug 2023 09:00:00 +0000;Tue, 25 Jul 2023 09:00:00 +0000;Fri, 21 Jul 2023 09:00:00 +0000;Tue, 18 Jul 2023 09:00:00 +0000;Fri, 14 Jul 2023 09:00:00 +0000;Tue, 11 Jul 2023 09:00:00 +0000;Fri, 7 Jul 2023 09:00:00 +0000;Tue, 4 Jul 2023 09:00:00 +0000;Fri, 30 Jun 2023 09:00:00 +0000;Tue, 27 Jun 2023 09:00:00 +0000;Fri, 23 Jun 2023 09:00:00 +0000
+Fri, 16 Feb 2024 18:39:33 +0000;Wed, 07 Feb 2024 22:59:08 +0000;Wed, 31 Jan 2024 21:05:35 +0000;Wed, 24 Jan 2024 21:18:24 +0000;Wed, 17 Jan 2024 22:22:37 +0000;Tue, 09 Jan 2024 23:11:06 +0000;Thu, 04 Jan 2024 21:55:36 +0000;Sun, 31 Dec 2023 15:00:00 +0000;Fri, 22 Dec 2023 00:09:21 +0000;Wed, 13 Dec 2023 22:49:42 +0000;Thu, 07 Dec 2023 23:01:46 +0000;Wed, 29 Nov 2023 21:48:07 +0000;Wed, 22 Nov 2023 20:46:00 +0000;Fri, 17 Nov 2023 14:00:00 +0000;Thu, 09 Nov 2023 14:57:00 +0000;Thu, 02 Nov 2023 20:55:00 +0000;Thu, 26 Oct 2023 18:01:00 +0000;Thu, 19 Oct 2023 16:53:00 +0000;Wed, 11 Oct 2023 19:29:00 +0000;Fri, 06 Oct 2023 18:37:00 +0000;Wed, 27 Sep 2023 23:15:00 +0000;Tue, 19 Sep 2023 15:52:00 +0000;Thu, 14 Sep 2023 19:14:00 +0000;Thu, 07 Sep 2023 17:33:00 +0000;Sat, 26 Aug 2023 15:04:00 +0000;Wed, 16 Aug 2023 19:52:00 +0000;Wed, 09 Aug 2023 19:57:00 +0000;Wed, 02 Aug 2023 17:14:00 +0000;Wed, 26 Jul 2023 18:20:00 +0000;Thu, 13 Jul 2023 19:36:00 +0000;Thu, 06 Jul 2023 02:26:00 +0000;Thu, 29 Jun 2023 18:28:00 +0000;Wed, 21 Jun 2023 20:06:00 +0000;Wed, 14 Jun 2023 19:24:00 +0000;Wed, 07 Jun 2023 19:48:00 +0000;Wed, 31 May 2023 19:43:00 +0000;Wed, 24 May 2023 17:51:00 +0000;Sun, 21 May 2023 18:55:00 +0000;Wed, 17 May 2023 19:24:00 +0000;Wed, 10 May 2023 16:57:00 +0000;Wed, 03 May 2023 16:18:00 +0000;Wed, 26 Apr 2023 20:05:00 +0000;Wed, 19 Apr 2023 20:29:00 +0000;Fri, 14 Apr 2023 12:51:00 +0000;Wed, 05 Apr 2023 18:13:00 +0000;Wed, 29 Mar 2023 15:54:00 +0000;Thu, 23 Mar 2023 01:26:00 +0000;Wed, 15 Mar 2023 20:11:00 +0000;Wed, 08 Mar 2023 19:10:00 +0000;Wed, 01 Mar 2023 21:54:00 +0000
+Thu, 15 Feb 2024 05:05:00 +0000;Mon, 12 Feb 2024 05:05:00 +0000;Thu, 8 Feb 2024 05:05:00 +0000;Mon, 5 Feb 2024 05:05:00 +0000;Thu, 1 Feb 2024 05:05:00 +0000;Mon, 29 Jan 2024 05:05:00 +0000;Thu, 25 Jan 2024 05:05:00 +0000;Mon, 22 Jan 2024 05:05:00 +0000;Fri, 19 Jan 2024 08:05:00 +0000;Thu, 18 Jan 2024 05:05:00 +0000;Mon, 15 Jan 2024 05:05:00 +0000;Thu, 11 Jan 2024 05:05:00 +0000;Mon, 8 Jan 2024 05:05:00 +0000;Thu, 4 Jan 2024 05:05:00 +0000;Mon, 1 Jan 2024 05:05:00 +0000;Thu, 28 Dec 2023 05:05:00 +0000;Mon, 25 Dec 2023 05:05:00 +0000;Thu, 21 Dec 2023 05:05:00 +0000;Wed, 20 Dec 2023 05:05:00 +0000;Mon, 18 Dec 2023 05:05:00 +0000;Thu, 14 Dec 2023 05:05:00 +0000;Mon, 11 Dec 2023 05:05:00 +0000;Thu, 7 Dec 2023 05:05:00 +0000;Mon, 4 Dec 2023 05:05:00 +0000;Thu, 30 Nov 2023 05:05:00 +0000;Mon, 27 Nov 2023 05:05:00 +0000;Thu, 23 Nov 2023 05:05:00 +0000;Mon, 20 Nov 2023 05:05:00 +0000;Thu, 16 Nov 2023 05:05:00 +0000;Mon, 13 Nov 2023 05:05:00 +0000;Thu, 9 Nov 2023 05:05:00 +0000;Mon, 6 Nov 2023 05:05:00 +0000;Thu, 2 Nov 2023 04:05:00 +0000;Mon, 30 Oct 2023 04:05:00 +0000;Fri, 27 Oct 2023 04:05:00 +0000;Thu, 26 Oct 2023 04:05:00 +0000;Mon, 23 Oct 2023 04:05:00 +0000;Thu, 19 Oct 2023 04:05:00 +0000;Mon, 16 Oct 2023 04:05:00 +0000;Thu, 12 Oct 2023 04:05:00 +0000;Mon, 9 Oct 2023 04:05:00 +0000;Thu, 5 Oct 2023 04:05:00 +0000;Mon, 2 Oct 2023 04:05:00 +0000;Thu, 28 Sep 2023 04:05:00 +0000;Mon, 25 Sep 2023 04:05:00 +0000;Thu, 21 Sep 2023 04:05:00 +0000;Mon, 18 Sep 2023 04:05:00 +0000;Thu, 14 Sep 2023 04:05:00 +0000;Mon, 11 Sep 2023 04:05:00 +0000;Thu, 7 Sep 2023 04:05:00 +0000
+Fri, 16 Feb 2024 19:00:00 -0000;Mon, 12 Feb 2024 08:01:00 -0000;Mon, 05 Feb 2024 08:01:00 -0000;Mon, 29 Jan 2024 08:01:00 -0000;Mon, 22 Jan 2024 08:02:00 -0000;Mon, 22 Jan 2024 08:01:00 -0000;Tue, 28 Nov 2023 11:00:00 -0000;Tue, 03 May 2022 07:01:00 -0000;Mon, 02 May 2022 07:01:00 -0000;Mon, 02 Aug 2021 07:00:00 -0000;Wed, 22 Aug 2018 07:05:00 -0000
+Fri, 16 Feb 2024 17:56:08 -0000;Fri, 16 Feb 2024 17:55:17 -0000;Fri, 16 Feb 2024 17:43:32 -0000;Fri, 16 Feb 2024 16:53:56 -0000;Fri, 16 Feb 2024 15:00:00 -0000;Fri, 16 Feb 2024 11:00:00 -0000;Fri, 16 Feb 2024 05:01:00 -0000;Thu, 15 Feb 2024 18:45:00 -0000;Thu, 15 Feb 2024 18:39:00 -0000;Thu, 15 Feb 2024 17:58:00 -0000;Thu, 15 Feb 2024 17:16:00 -0000;Thu, 15 Feb 2024 16:40:00 -0000;Wed, 14 Feb 2024 18:11:00 -0000;Wed, 14 Feb 2024 18:08:00 -0000;Wed, 14 Feb 2024 17:30:00 -0000;Wed, 14 Feb 2024 17:15:00 -0000;Wed, 14 Feb 2024 16:10:00 -0000;Tue, 13 Feb 2024 19:18:20 -0000;Tue, 13 Feb 2024 18:27:00 -0000;Tue, 13 Feb 2024 18:22:22 -0000;Tue, 13 Feb 2024 17:39:00 -0000;Tue, 13 Feb 2024 16:50:00 -0000;Tue, 13 Feb 2024 16:32:00 -0000;Mon, 12 Feb 2024 18:30:00 -0000;Mon, 12 Feb 2024 18:15:00 -0000;Mon, 12 Feb 2024 17:30:00 -0000;Mon, 12 Feb 2024 16:50:00 -0000;Mon, 12 Feb 2024 16:05:00 -0000;Mon, 12 Feb 2024 14:53:00 -0000;Fri, 09 Feb 2024 23:37:10 -0000;Fri, 09 Feb 2024 23:22:31 -0000;Fri, 09 Feb 2024 20:12:06 -0000;Fri, 09 Feb 2024 15:01:00 -0000;Fri, 09 Feb 2024 13:45:00 -0000;Fri, 09 Feb 2024 00:41:00 -0000;Fri, 09 Feb 2024 00:01:00 -0000;Thu, 08 Feb 2024 23:20:15 -0000;Thu, 08 Feb 2024 14:25:00 -0000;Thu, 08 Feb 2024 11:45:56 -0000;Thu, 08 Feb 2024 00:00:00 -0000;Wed, 07 Feb 2024 19:41:00 -0000;Wed, 07 Feb 2024 18:04:00 -0000;Wed, 07 Feb 2024 17:35:00 -0000;Wed, 07 Feb 2024 16:44:00 -0000;Wed, 07 Feb 2024 14:53:00 -0000;Tue, 06 Feb 2024 21:45:36 -0000;Tue, 06 Feb 2024 19:38:46 -0000;Tue, 06 Feb 2024 18:40:00 -0000;Tue, 06 Feb 2024 17:47:00 -0000;Tue, 06 Feb 2024 17:07:00 -0000
+Sun, 18 Feb 2024 11:00:00 -0000;Sat, 17 Feb 2024 08:30:00 -0000;Fri, 16 Feb 2024 17:38:31 -0000;Thu, 15 Feb 2024 15:36:40 -0000;Wed, 14 Feb 2024 18:01:59 -0000;Wed, 14 Feb 2024 17:37:00 -0000;Tue, 13 Feb 2024 15:22:57 -0000;Sat, 10 Feb 2024 11:00:00 -0000;Fri, 09 Feb 2024 17:28:21 -0000;Thu, 08 Feb 2024 16:01:45 -0000;Wed, 07 Feb 2024 15:03:24 -0000;Tue, 06 Feb 2024 15:33:35 -0000;Mon, 05 Feb 2024 18:17:28 -0000;Sun, 04 Feb 2024 11:00:00 -0000;Sat, 03 Feb 2024 08:30:00 -0000;Fri, 02 Feb 2024 15:36:42 -0000;Thu, 01 Feb 2024 14:38:51 -0000;Wed, 31 Jan 2024 15:09:19 -0000;Tue, 30 Jan 2024 14:43:43 -0000;Mon, 29 Jan 2024 15:37:28 -0000;Sat, 27 Jan 2024 08:30:00 -0000;Fri, 26 Jan 2024 15:12:04 -0000;Thu, 25 Jan 2024 14:32:26 -0000;Wed, 24 Jan 2024 15:17:01 -0000;Tue, 23 Jan 2024 15:37:58 -0000;Mon, 22 Jan 2024 14:35:00 -0000;Sun, 21 Jan 2024 11:00:00 -0000;Sat, 20 Jan 2024 08:30:00 -0000;Fri, 19 Jan 2024 15:24:00 -0000;Thu, 18 Jan 2024 15:16:08 -0000;Wed, 17 Jan 2024 18:41:28 -0000;Tue, 16 Jan 2024 14:31:38 -0000;Mon, 15 Jan 2024 17:01:39 -0000;Sun, 14 Jan 2024 11:00:00 -0000;Sat, 13 Jan 2024 11:30:00 -0000;Fri, 12 Jan 2024 14:54:25 -0000;Thu, 11 Jan 2024 15:11:10 -0000;Wed, 10 Jan 2024 14:28:43 -0000;Tue, 09 Jan 2024 15:53:59 -0000;Mon, 08 Jan 2024 15:56:21 -0000;Sat, 06 Jan 2024 08:30:00 -0000;Fri, 05 Jan 2024 17:17:44 -0000;Thu, 04 Jan 2024 17:19:16 -0000;Wed, 03 Jan 2024 17:20:53 -0000;Fri, 29 Dec 2023 14:30:00 -0000;Thu, 28 Dec 2023 14:30:00 -0000;Wed, 27 Dec 2023 14:30:00 -0000;Tue, 26 Dec 2023 14:30:00 -0000;Fri, 22 Dec 2023 17:24:46 -0000;Thu, 21 Dec 2023 17:23:20 -0000
+Mon, 05 Feb 2024 14:00:00 +0000;Mon, 22 Jan 2024 09:00:00 +0000;Sun, 07 Jan 2024 19:00:00 +0000;Wed, 27 Dec 2023 07:00:00 +0000;Mon, 11 Dec 2023 07:00:00 +0000;Mon, 27 Nov 2023 07:55:28 +0000;Mon, 13 Nov 2023 13:44:42 +0000;Mon, 30 Oct 2023 06:00:00 +0000;Tue, 17 Oct 2023 00:19:32 +0000;Mon, 02 Oct 2023 06:00:00 +0000;Mon, 18 Sep 2023 06:03:41 +0000;Tue, 05 Sep 2023 09:00:00 +0000;Mon, 21 Aug 2023 07:11:17 +0000;Mon, 07 Aug 2023 06:15:03 +0000;Mon, 24 Jul 2023 06:00:00 +0000;Mon, 10 Jul 2023 06:00:00 +0000;Mon, 26 Jun 2023 06:00:00 +0000;Mon, 12 Jun 2023 06:00:00 +0000;Mon, 29 May 2023 06:00:00 +0000;Mon, 15 May 2023 06:00:00 +0000;Mon, 01 May 2023 06:00:00 +0000;Mon, 17 Apr 2023 06:00:00 +0000;Mon, 03 Apr 2023 06:00:00 +0000;Mon, 20 Mar 2023 06:00:00 +0000;Mon, 06 Mar 2023 07:00:00 +0000;Tue, 21 Feb 2023 07:00:00 +0000;Mon, 06 Feb 2023 07:00:00 +0000;Mon, 23 Jan 2023 06:00:00 +0000;Mon, 16 Jan 2023 06:00:00 +0000;Tue, 03 Jan 2023 06:00:00 +0000;Mon, 05 Dec 2022 06:00:00 +0000;Mon, 21 Nov 2022 07:00:00 +0000;Mon, 07 Nov 2022 07:00:00 +0000;Mon, 24 Oct 2022 06:00:00 +0000;Mon, 03 Oct 2022 06:00:00 +0000;Mon, 12 Sep 2022 06:00:00 +0000;Mon, 29 Aug 2022 06:00:00 +0000;Mon, 15 Aug 2022 06:00:00 +0000;Mon, 01 Aug 2022 06:00:00 +0000;Mon, 18 Jul 2022 06:00:00 +0000;Tue, 05 Jul 2022 06:00:00 +0000;Mon, 20 Jun 2022 06:00:00 +0000;Tue, 07 Jun 2022 06:00:00 +0000;Fri, 03 Jun 2022 16:00:04 +0000;Mon, 23 May 2022 06:00:00 +0000;Mon, 09 May 2022 06:00:00 +0000;Mon, 25 Apr 2022 06:00:00 +0000;Mon, 11 Apr 2022 06:00:00 +0000;Wed, 23 Mar 2022 06:00:00 +0000;Mon, 14 Mar 2022 06:00:00 +0000
+Thu, 15 Feb 2024 10:00:00 +0000;Thu, 8 Feb 2024 10:00:00 +0000;Tue, 17 Oct 2023 16:00:00 +0000;Thu, 20 Jul 2023 09:00:00 +0000;Thu, 13 Jul 2023 09:00:00 +0000;Thu, 6 Jul 2023 09:00:00 +0000;Fri, 30 Jun 2023 09:00:00 +0000;Thu, 29 Jun 2023 09:00:00 +0000;Thu, 22 Jun 2023 09:00:00 +0000;Thu, 15 Jun 2023 09:00:00 +0000;Thu, 8 Jun 2023 09:00:00 +0000;Thu, 1 Jun 2023 09:00:00 +0000;Thu, 25 May 2023 09:00:00 +0000;Thu, 18 May 2023 09:00:00 +0000;Thu, 11 May 2023 09:00:00 +0000;Thu, 4 May 2023 09:00:00 +0000;Thu, 27 Apr 2023 09:00:00 +0000;Thu, 20 Apr 2023 09:00:00 +0000;Thu, 13 Apr 2023 09:00:00 +0000;Thu, 6 Apr 2023 09:00:00 +0000;Thu, 30 Mar 2023 09:00:00 +0000;Thu, 23 Mar 2023 09:00:00 +0000;Thu, 16 Mar 2023 09:00:00 +0000;Thu, 9 Mar 2023 10:00:00 +0000;Thu, 2 Mar 2023 10:00:00 +0000;Thu, 23 Feb 2023 10:00:00 +0000;Thu, 16 Feb 2023 10:00:00 +0000;Thu, 9 Feb 2023 10:00:00 +0000;Thu, 2 Feb 2023 10:00:00 +0000;Thu, 26 Jan 2023 10:00:00 +0000;Thu, 19 Jan 2023 10:00:00 +0000;Tue, 17 Jan 2023 22:00:00 +0000;Thu, 12 Jan 2023 10:00:00 +0000;Thu, 5 Jan 2023 10:00:00 +0000;Thu, 29 Dec 2022 10:00:00 +0000;Thu, 22 Dec 2022 10:00:00 +0000;Thu, 15 Dec 2022 10:00:00 +0000;Thu, 8 Dec 2022 10:00:00 +0000;Thu, 1 Dec 2022 10:00:00 +0000;Thu, 24 Nov 2022 10:00:00 +0000;Thu, 17 Nov 2022 10:00:00 +0000;Thu, 10 Nov 2022 10:00:00 +0000;Thu, 3 Nov 2022 09:00:00 +0000;Thu, 27 Oct 2022 09:00:00 +0000;Thu, 20 Oct 2022 09:00:00 +0000;Thu, 13 Oct 2022 09:00:00 +0000;Thu, 6 Oct 2022 09:00:00 +0000;Thu, 29 Sep 2022 09:00:00 +0000;Tue, 27 Sep 2022 09:00:00 +0000;Thu, 22 Sep 2022 09:00:00 +0000
+Fri, 16 Feb 2024 20:31:28 +0000;Thu, 15 Feb 2024 19:00:00 +0000;Wed, 14 Feb 2024 20:26:39 +0000;Tue, 13 Feb 2024 20:35:00 +0000;Mon, 12 Feb 2024 20:33:18 +0000;Fri, 9 Feb 2024 20:24:24 +0000;Thu, 8 Feb 2024 19:00:00 +0000;Wed, 7 Feb 2024 19:56:45 +0000;Wed, 7 Feb 2024 11:00:00 +0000;Tue, 6 Feb 2024 20:07:45 +0000;Mon, 5 Feb 2024 20:20:57 +0000;Fri, 2 Feb 2024 20:26:20 +0000;Thu, 1 Feb 2024 20:18:10 +0000;Wed, 31 Jan 2024 20:08:01 +0000;Tue, 30 Jan 2024 19:45:32 +0000;Mon, 29 Jan 2024 19:26:51 +0000;Fri, 26 Jan 2024 19:00:00 +0000;Thu, 25 Jan 2024 20:11:50 +0000;Wed, 24 Jan 2024 20:07:55 +0000;Tue, 23 Jan 2024 20:14:04 +0000;Mon, 22 Jan 2024 20:44:35 +0000;Fri, 19 Jan 2024 19:00:00 +0000;Thu, 18 Jan 2024 20:03:11 +0000;Wed, 17 Jan 2024 20:31:41 +0000;Tue, 16 Jan 2024 20:14:49 +0000;Mon, 15 Jan 2024 20:26:39 +0000;Fri, 12 Jan 2024 19:57:21 +0000;Thu, 11 Jan 2024 20:11:51 +0000;Wed, 10 Jan 2024 20:03:04 +0000;Tue, 9 Jan 2024 20:16:47 +0000;Mon, 8 Jan 2024 20:11:15 +0000;Fri, 5 Jan 2024 19:47:36 +0000;Thu, 4 Jan 2024 20:37:01 +0000;Wed, 3 Jan 2024 20:03:23 +0000;Tue, 2 Jan 2024 20:16:23 +0000;Fri, 22 Dec 2023 19:00:00 +0000;Thu, 21 Dec 2023 19:00:00 +0000;Wed, 20 Dec 2023 19:00:00 +0000;Tue, 19 Dec 2023 19:00:00 +0000;Mon, 18 Dec 2023 19:00:00 +0000;Fri, 15 Dec 2023 20:33:27 +0000;Thu, 14 Dec 2023 19:51:54 +0000;Wed, 13 Dec 2023 19:51:07 +0000;Tue, 12 Dec 2023 19:42:11 +0000;Mon, 11 Dec 2023 21:00:51 +0000;Fri, 8 Dec 2023 20:09:33 +0000;Thu, 7 Dec 2023 19:57:03 +0000;Thu, 7 Dec 2023 04:57:08 +0000;Wed, 6 Dec 2023 20:05:26 +0000;Tue, 5 Dec 2023 20:10:56 +0000
+Sun, 18 Feb 2024 01:00:00 -0600;Sat, 17 Feb 2024 01:00:00 -0600;Fri, 16 Feb 2024 01:00:00 -0600;Thu, 15 Feb 2024 01:00:00 -0600;Wed, 14 Feb 2024 01:00:00 -0600;Tue, 13 Feb 2024 01:00:00 -0600;Mon, 12 Feb 2024 01:00:00 -0600;Sun, 11 Feb 2024 01:00:00 -0600;Sat, 10 Feb 2024 01:00:00 -0600;Fri, 09 Feb 2024 01:00:00 -0600;Thu, 08 Feb 2024 01:00:00 -0600;Wed, 07 Feb 2024 01:00:00 -0600;Tue, 06 Feb 2024 01:00:00 -0600;Mon, 05 Feb 2024 01:00:00 -0600;Sun, 04 Feb 2024 01:00:00 -0600;Sat, 03 Feb 2024 01:00:00 -0600;Fri, 02 Feb 2024 01:00:00 -0600;Thu, 01 Feb 2024 01:00:00 -0600;Wed, 31 Jan 2024 03:00:00 -0600;Wed, 31 Jan 2024 01:00:00 -0600;Tue, 30 Jan 2024 01:00:00 -0600;Mon, 29 Jan 2024 01:00:00 -0600;Sun, 28 Jan 2024 01:00:00 -0600;Sat, 27 Jan 2024 01:00:00 -0600;Fri, 26 Jan 2024 01:00:00 -0600;Thu, 25 Jan 2024 01:00:00 -0600;Wed, 24 Jan 2024 01:00:00 -0600;Tue, 23 Jan 2024 01:00:00 -0600;Mon, 22 Jan 2024 01:00:00 -0600;Sun, 21 Jan 2024 01:00:00 -0600;Sat, 20 Jan 2024 01:00:00 -0600;Fri, 19 Jan 2024 01:00:00 -0600;Thu, 18 Jan 2024 01:00:00 -0600;Wed, 17 Jan 2024 01:00:00 -0600;Tue, 16 Jan 2024 01:00:00 -0600;Mon, 15 Jan 2024 01:00:00 -0600;Sun, 14 Jan 2024 01:00:00 -0600;Sat, 13 Jan 2024 01:00:00 -0600;Fri, 12 Jan 2024 01:00:00 -0600;Thu, 11 Jan 2024 01:00:00 -0600;Wed, 10 Jan 2024 01:00:00 -0600;Tue, 09 Jan 2024 01:00:00 -0600;Mon, 08 Jan 2024 01:00:00 -0600;Sun, 07 Jan 2024 01:00:00 -0600;Sat, 06 Jan 2024 01:00:00 -0600;Fri, 05 Jan 2024 01:00:00 -0600;Thu, 04 Jan 2024 01:00:00 -0600;Wed, 03 Jan 2024 01:00:00 -0600;Tue, 02 Jan 2024 01:00:00 -0600;Mon, 01 Jan 2024 01:30:00 -0600
+Fri, 16 Feb 2024 08:00:00 +0000;Mon, 12 Feb 2024 08:00:00 +0000;Fri, 09 Feb 2024 08:00:00 +0000;Mon, 05 Feb 2024 08:00:00 +0000;Fri, 02 Feb 2024 08:00:00 +0000;Mon, 29 Jan 2024 08:00:00 +0000;Fri, 26 Jan 2024 08:00:00 +0000;Mon, 22 Jan 2024 08:00:00 +0000;Fri, 19 Jan 2024 08:00:00 +0000;Mon, 15 Jan 2024 08:00:00 +0000;Fri, 12 Jan 2024 08:00:00 +0000;Mon, 08 Jan 2024 08:00:00 +0000;Fri, 05 Jan 2024 08:00:00 +0000;Mon, 01 Jan 2024 08:00:00 +0000;Fri, 29 Dec 2023 08:00:00 +0000;Mon, 25 Dec 2023 08:00:00 +0000;Fri, 22 Dec 2023 08:00:00 +0000;Mon, 18 Dec 2023 08:00:00 +0000;Fri, 15 Dec 2023 08:00:00 +0000;Mon, 11 Dec 2023 08:00:00 +0000;Fri, 08 Dec 2023 08:00:00 +0000;Mon, 04 Dec 2023 08:00:00 +0000;Fri, 01 Dec 2023 08:00:00 +0000;Mon, 27 Nov 2023 08:00:00 +0000;Fri, 24 Nov 2023 08:00:00 +0000;Mon, 20 Nov 2023 08:00:00 +0000;Fri, 17 Nov 2023 08:00:00 +0000;Mon, 13 Nov 2023 08:00:00 +0000;Fri, 10 Nov 2023 08:00:00 +0000;Mon, 06 Nov 2023 08:00:00 +0000;Fri, 03 Nov 2023 07:00:00 +0000;Mon, 30 Oct 2023 07:00:00 +0000;Fri, 27 Oct 2023 07:00:00 +0000;Mon, 23 Oct 2023 07:00:00 +0000;Fri, 20 Oct 2023 07:00:00 +0000;Mon, 16 Oct 2023 07:00:00 +0000;Fri, 13 Oct 2023 07:00:00 +0000;Mon, 09 Oct 2023 07:00:00 +0000;Fri, 06 Oct 2023 07:00:00 +0000;Mon, 02 Oct 2023 07:00:00 +0000;Fri, 29 Sep 2023 07:00:00 +0000;Mon, 25 Sep 2023 07:00:00 +0000;Fri, 22 Sep 2023 07:00:00 +0000;Mon, 18 Sep 2023 07:00:00 +0000;Fri, 15 Sep 2023 07:00:00 +0000;Mon, 11 Sep 2023 07:00:00 +0000;Fri, 08 Sep 2023 07:00:00 +0000;Mon, 04 Sep 2023 07:00:00 +0000;Fri, 01 Sep 2023 07:00:00 +0000;Mon, 28 Aug 2023 07:00:00 +0000
+Fri, 16 Feb 2024 06:03:04 +0000;Wed, 14 Feb 2024 06:04:59 +0000;Mon, 12 Feb 2024 11:31:17 +0000;Fri, 9 Feb 2024 05:01:19 +0000;Wed, 7 Feb 2024 10:20:48 +0000;Mon, 5 Feb 2024 07:22:22 +0000;Fri, 2 Feb 2024 05:00:00 +0000;Wed, 31 Jan 2024 05:00:00 +0000;Mon, 29 Jan 2024 07:49:39 +0000;Fri, 26 Jan 2024 03:31:42 +0000;Wed, 24 Jan 2024 04:30:00 +0000;Mon, 22 Jan 2024 09:08:11 +0000;Fri, 19 Jan 2024 05:31:33 +0000;Wed, 17 Jan 2024 05:00:00 +0000;Mon, 15 Jan 2024 09:48:29 +0000;Fri, 12 Jan 2024 06:59:14 +0000;Wed, 10 Jan 2024 05:08:14 +0000;Mon, 8 Jan 2024 09:00:11 +0000;Fri, 5 Jan 2024 05:00:00 +0000;Tue, 2 Jan 2024 09:59:02 +0000;Fri, 29 Dec 2023 07:53:23 +0000;Tue, 26 Dec 2023 10:19:24 +0000;Fri, 22 Dec 2023 05:03:12 +0000;Wed, 20 Dec 2023 05:00:00 +0000;Mon, 18 Dec 2023 09:29:34 +0000;Fri, 15 Dec 2023 07:13:13 +0000;Wed, 13 Dec 2023 05:16:40 +0000;Mon, 11 Dec 2023 08:33:48 +0000;Fri, 8 Dec 2023 06:16:24 +0000;Wed, 6 Dec 2023 05:47:57 +0000;Mon, 4 Dec 2023 08:53:08 +0000;Fri, 1 Dec 2023 06:10:12 +0000;Wed, 29 Nov 2023 04:56:01 +0000;Mon, 27 Nov 2023 09:07:05 +0000;Wed, 22 Nov 2023 06:07:17 +0000;Mon, 20 Nov 2023 08:41:28 +0000;Fri, 17 Nov 2023 07:22:53 +0000;Wed, 15 Nov 2023 06:46:44 +0000;Mon, 13 Nov 2023 07:36:15 +0000;Fri, 10 Nov 2023 05:44:22 +0000;Wed, 8 Nov 2023 02:29:00 +0000;Mon, 6 Nov 2023 08:04:51 +0000;Fri, 3 Nov 2023 06:58:45 +0000;Wed, 1 Nov 2023 12:35:28 +0000;Mon, 30 Oct 2023 07:44:34 +0000;Fri, 27 Oct 2023 06:32:28 +0000;Wed, 25 Oct 2023 07:01:43 +0000;Mon, 23 Oct 2023 07:07:18 +0000;Fri, 20 Oct 2023 06:41:08 +0000;Wed, 18 Oct 2023 05:44:40 +0000
+Thu, 15 Feb 2024 10:00:00 -0000;Mon, 12 Feb 2024 10:00:00 -0000;Thu, 08 Feb 2024 10:00:00 -0000;Mon, 05 Feb 2024 10:00:00 -0000;Thu, 01 Feb 2024 10:00:00 -0000;Mon, 29 Jan 2024 10:00:00 -0000;Thu, 25 Jan 2024 10:00:00 -0000;Mon, 22 Jan 2024 10:00:00 -0000;Thu, 18 Jan 2024 10:00:00 -0000;Tue, 16 Jan 2024 10:00:00 -0000;Fri, 12 Jan 2024 22:00:00 -0000;Wed, 10 Jan 2024 22:00:00 -0000;Tue, 09 Jan 2024 05:00:00 -0000;Mon, 19 Dec 2022 10:00:00 -0000;Mon, 12 Dec 2022 00:00:00 -0000;Mon, 26 Sep 2022 09:00:00 -0000;Mon, 27 Jun 2022 09:00:00 -0000;Thu, 23 Jun 2022 09:00:00 -0000;Mon, 20 Jun 2022 09:00:00 -0000;Thu, 16 Jun 2022 09:00:00 -0000;Mon, 13 Jun 2022 09:00:00 -0000;Thu, 09 Jun 2022 09:00:00 -0000;Mon, 06 Jun 2022 09:00:00 -0000;Thu, 02 Jun 2022 09:00:00 -0000;Thu, 26 May 2022 09:00:00 -0000;Mon, 23 May 2022 09:00:00 -0000;Thu, 19 May 2022 09:00:00 -0000;Mon, 16 May 2022 09:00:00 -0000;Thu, 12 May 2022 09:00:00 -0000;Mon, 09 May 2022 09:00:00 -0000;Thu, 05 May 2022 09:00:00 -0000;Mon, 02 May 2022 09:00:00 -0000;Thu, 28 Apr 2022 09:00:00 -0000;Mon, 25 Apr 2022 09:00:00 -0000;Thu, 21 Apr 2022 09:00:00 -0000;Mon, 18 Apr 2022 09:00:00 -0000;Thu, 14 Apr 2022 09:00:00 -0000;Mon, 11 Apr 2022 09:00:00 -0000;Thu, 07 Apr 2022 09:00:00 -0000;Mon, 04 Apr 2022 09:00:00 -0000;Thu, 31 Mar 2022 09:00:00 -0000;Mon, 28 Mar 2022 09:00:00 -0000;Thu, 24 Mar 2022 09:00:00 -0000;Mon, 21 Mar 2022 09:00:00 -0000;Mon, 14 Mar 2022 09:00:00 -0000;Mon, 07 Mar 2022 17:00:00 -0000;Thu, 24 Feb 2022 23:13:41 -0000
+Sun, 11 Feb 2024 18:00:00 -0500;Sun, 04 Feb 2024 18:00:00 -0500;Sun, 28 Jan 2024 18:00:00 -0500;Sun, 21 Jan 2024 18:00:00 -0500;Sun, 24 Dec 2023 18:00:00 -0500;Fri, 22 Dec 2023 18:00:00 -0500;Sun, 17 Dec 2023 18:00:00 -0500;Sun, 03 Dec 2023 18:00:00 -0500;Sun, 26 Nov 2023 18:00:00 -0500;Sun, 19 Nov 2023 18:00:00 -0500
+Fri, 16 Feb 2024 16:23:39 -0000;Thu, 15 Feb 2024 16:54:16 -0000;Wed, 14 Feb 2024 16:58:01 -0000;Tue, 13 Feb 2024 16:42:11 -0000;Mon, 12 Feb 2024 17:04:44 -0000;Fri, 09 Feb 2024 16:50:51 -0000;Thu, 08 Feb 2024 17:02:31 -0000;Wed, 07 Feb 2024 17:41:36 -0000;Tue, 06 Feb 2024 17:16:29 -0000;Mon, 05 Feb 2024 17:22:35 -0000;Fri, 02 Feb 2024 16:56:12 -0000;Thu, 01 Feb 2024 17:01:31 -0000;Wed, 31 Jan 2024 17:13:00 -0000;Tue, 30 Jan 2024 16:49:53 -0000;Mon, 29 Jan 2024 16:53:19 -0000;Fri, 26 Jan 2024 16:54:26 -0000;Thu, 25 Jan 2024 16:54:03 -0000;Wed, 24 Jan 2024 17:12:24 -0000;Tue, 23 Jan 2024 17:05:08 -0000;Mon, 22 Jan 2024 17:03:36 -0000;Fri, 19 Jan 2024 16:25:27 -0000;Thu, 18 Jan 2024 17:00:27 -0000;Wed, 17 Jan 2024 16:58:57 -0000;Tue, 16 Jan 2024 19:27:07 -0000;Fri, 12 Jan 2024 18:11:14 -0000;Thu, 11 Jan 2024 12:41:58 -0000;Wed, 10 Jan 2024 17:01:25 -0000;Tue, 09 Jan 2024 17:14:00 -0000;Mon, 08 Jan 2024 17:02:27 -0000;Fri, 05 Jan 2024 17:24:16 -0000;Thu, 04 Jan 2024 17:02:44 -0000;Fri, 29 Dec 2023 18:54:58 -0000;Fri, 15 Dec 2023 17:07:29 -0000;Thu, 14 Dec 2023 16:56:00 -0000;Wed, 13 Dec 2023 16:34:45 -0000;Tue, 12 Dec 2023 16:49:37 -0000;Mon, 11 Dec 2023 16:57:47 -0000;Fri, 08 Dec 2023 16:43:27 -0000;Wed, 06 Dec 2023 16:53:02 -0000;Tue, 05 Dec 2023 16:23:27 -0000;Mon, 04 Dec 2023 17:02:18 -0000;Fri, 01 Dec 2023 17:10:53 -0000;Thu, 30 Nov 2023 17:06:19 -0000;Wed, 29 Nov 2023 16:54:50 -0000;Tue, 28 Nov 2023 17:03:00 -0000;Mon, 27 Nov 2023 17:18:36 -0000;Tue, 21 Nov 2023 16:49:30 -0000;Mon, 20 Nov 2023 16:46:00 -0000;Fri, 17 Nov 2023 16:58:15 -0000;Thu, 16 Nov 2023 17:04:36 -0000
+Wed, 14 Feb 2024 08:00:00 +0000;Wed, 7 Feb 2024 08:00:00 +0000;Wed, 31 Jan 2024 08:00:00 +0000;Wed, 24 Jan 2024 08:00:00 +0000;Wed, 17 Jan 2024 08:00:00 +0000;Wed, 10 Jan 2024 08:05:00 +0000;Wed, 10 Jan 2024 08:00:00 +0000;Thu, 4 Jan 2024 08:00:00 +0000;Wed, 3 Jan 2024 08:00:00 +0000;Wed, 27 Dec 2023 08:00:00 +0000;Wed, 20 Dec 2023 08:00:00 +0000;Wed, 13 Dec 2023 08:00:00 +0000;Wed, 29 Nov 2023 08:00:00 +0000;Wed, 22 Nov 2023 08:00:00 +0000;Wed, 15 Nov 2023 08:00:00 +0000;Wed, 8 Nov 2023 08:00:00 +0000;Wed, 1 Nov 2023 07:00:00 +0000;Wed, 25 Oct 2023 07:00:00 +0000;Wed, 18 Oct 2023 07:00:00 +0000;Wed, 11 Oct 2023 07:00:00 +0000;Wed, 4 Oct 2023 07:00:00 +0000;Wed, 27 Sep 2023 07:00:00 +0000;Wed, 13 Sep 2023 07:00:00 +0000;Wed, 6 Sep 2023 07:00:00 +0000;Wed, 30 Aug 2023 07:00:00 +0000;Wed, 23 Aug 2023 07:00:00 +0000;Wed, 16 Aug 2023 07:00:00 +0000;Wed, 9 Aug 2023 07:05:00 +0000;Wed, 9 Aug 2023 07:00:00 +0000;Wed, 2 Aug 2023 07:00:00 +0000;Wed, 26 Jul 2023 07:00:00 +0000;Wed, 19 Jul 2023 07:00:00 +0000;Wed, 12 Jul 2023 07:00:00 +0000;Wed, 5 Jul 2023 07:00:00 +0000;Wed, 28 Jun 2023 07:00:00 +0000;Wed, 21 Jun 2023 07:00:00 +0000;Wed, 14 Jun 2023 07:00:00 +0000;Wed, 7 Jun 2023 07:00:00 +0000;Wed, 24 May 2023 07:05:00 +0000;Wed, 24 May 2023 07:00:00 +0000;Wed, 17 May 2023 07:00:00 +0000;Wed, 10 May 2023 07:00:00 +0000;Wed, 3 May 2023 07:00:00 +0000;Wed, 26 Apr 2023 07:00:00 +0000;Wed, 19 Apr 2023 07:00:00 +0000;Wed, 12 Apr 2023 07:00:00 +0000;Wed, 5 Apr 2023 07:00:00 +0000;Wed, 29 Mar 2023 07:00:00 +0000;Wed, 22 Mar 2023 07:05:00 +0000;Wed, 22 Mar 2023 07:00:00 +0000
+Thu, 15 Feb 2024 04:00:00 +0000;Thu, 8 Feb 2024 04:00:00 +0000;Mon, 5 Feb 2024 05:05:00 +0000;Thu, 1 Feb 2024 04:00:00 +0000;Thu, 25 Jan 2024 04:00:00 +0000;Mon, 22 Jan 2024 05:05:00 +0000;Thu, 18 Jan 2024 04:00:00 +0000;Thu, 11 Jan 2024 04:00:00 +0000;Thu, 4 Jan 2024 04:00:00 +0000;Thu, 28 Dec 2023 04:00:00 +0000;Thu, 21 Dec 2023 04:00:00 +0000;Thu, 14 Dec 2023 04:00:00 +0000;Thu, 7 Dec 2023 04:00:00 +0000;Thu, 30 Nov 2023 04:00:00 +0000;Thu, 23 Nov 2023 04:00:00 +0000;Sun, 19 Nov 2023 05:05:00 +0000;Thu, 16 Nov 2023 04:00:00 +0000;Thu, 9 Nov 2023 04:00:00 +0000;Thu, 2 Nov 2023 03:00:00 +0000;Thu, 26 Oct 2023 03:00:00 +0000;Thu, 19 Oct 2023 03:00:00 +0000;Thu, 12 Oct 2023 03:00:00 +0000;Tue, 10 Oct 2023 01:37:38 +0000;Thu, 5 Oct 2023 03:00:00 +0000;Thu, 28 Sep 2023 03:00:00 +0000;Thu, 21 Sep 2023 03:00:00 +0000;Thu, 14 Sep 2023 03:00:00 +0000;Thu, 7 Sep 2023 03:00:00 +0000;Thu, 31 Aug 2023 03:00:00 +0000;Thu, 24 Aug 2023 03:00:00 +0000;Thu, 17 Aug 2023 03:00:00 +0000;Thu, 10 Aug 2023 03:00:00 +0000;Sun, 6 Aug 2023 21:00:00 +0000;Thu, 3 Aug 2023 03:00:00 +0000;Thu, 27 Jul 2023 03:00:00 +0000;Thu, 20 Jul 2023 03:00:00 +0000;Thu, 13 Jul 2023 03:00:00 +0000;Thu, 6 Jul 2023 03:00:00 +0000;Thu, 29 Jun 2023 03:00:00 +0000;Thu, 22 Jun 2023 03:00:00 +0000;Thu, 15 Jun 2023 03:00:00 +0000;Thu, 8 Jun 2023 03:00:00 +0000;Thu, 1 Jun 2023 03:00:00 +0000;Thu, 25 May 2023 03:00:00 +0000;Thu, 18 May 2023 03:00:00 +0000;Thu, 11 May 2023 03:00:00 +0000;Thu, 4 May 2023 03:00:00 +0000;Thu, 27 Apr 2023 03:00:00 +0000;Thu, 20 Apr 2023 03:00:00 +0000;Thu, 13 Apr 2023 03:00:00 +0000
+
+Fri, 16 Feb 2024 00:01:00 -0500;Thu, 15 Feb 2024 00:01:00 -0500;Tue, 13 Feb 2024 00:01:00 -0500;Fri, 09 Feb 2024 07:41:57 -0500;Thu, 08 Feb 2024 00:01:00 -0500;Tue, 06 Feb 2024 00:01:00 -0500;Fri, 02 Feb 2024 11:07:07 -0500;Thu, 01 Feb 2024 00:01:00 -0500;Wed, 31 Jan 2024 00:01:00 -0500;Tue, 30 Jan 2024 00:01:00 -0500;Fri, 26 Jan 2024 08:28:31 -0500;Thu, 25 Jan 2024 00:01:00 -0500;Wed, 24 Jan 2024 00:01:00 -0500;Tue, 23 Jan 2024 00:01:00 -0500;Fri, 19 Jan 2024 00:01:00 -0500;Thu, 18 Jan 2024 00:01:00 -0500;Tue, 16 Jan 2024 00:01:00 -0500;Fri, 12 Jan 2024 00:01:00 -0500;Thu, 11 Jan 2024 00:01:00 -0500;Wed, 10 Jan 2024 00:01:00 -0500;Tue, 09 Jan 2024 00:01:00 -0500;Fri, 05 Jan 2024 00:01:00 -0500;Thu, 04 Jan 2024 00:01:00 -0500;Tue, 02 Jan 2024 00:01:00 -0500;Fri, 29 Dec 2023 12:44:10 -0500;Thu, 28 Dec 2023 00:01:00 -0500;Tue, 26 Dec 2023 00:01:00 -0500;Fri, 22 Dec 2023 16:04:23 -0500;Thu, 21 Dec 2023 15:29:13 -0500;Tue, 19 Dec 2023 14:59:45 -0500;Fri, 15 Dec 2023 00:01:00 -0500;Thu, 14 Dec 2023 08:15:28 -0500;Wed, 13 Dec 2023 18:40:23 -0500;Tue, 12 Dec 2023 00:01:00 -0500;Fri, 08 Dec 2023 00:01:00 -0500;Thu, 07 Dec 2023 00:01:00 -0500;Tue, 05 Dec 2023 00:01:00 -0500;Fri, 01 Dec 2023 00:01:00 -0500;Thu, 30 Nov 2023 00:01:00 -0500;Tue, 28 Nov 2023 00:01:00 -0500;Fri, 24 Nov 2023 00:01:00 -0500;Thu, 23 Nov 2023 00:01:00 -0500;Tue, 21 Nov 2023 00:01:00 -0500;Fri, 17 Nov 2023 00:01:00 -0500;Thu, 16 Nov 2023 00:01:00 -0500;Tue, 14 Nov 2023 00:01:00 -0500;Fri, 10 Nov 2023 00:01:00 -0500;Thu, 09 Nov 2023 00:01:00 -0500;Tue, 07 Nov 2023 00:01:00 -0500;Fri, 03 Nov 2023 00:01:00 -0400
+Tue, 13 Feb 2024 11:00:00 -0000;Tue, 06 Feb 2024 11:00:00 -0000;Tue, 23 Jan 2024 11:00:00 -0000;Fri, 01 Oct 2021 21:48:00 -0000;Thu, 08 Jul 2021 08:00:00 -0000;Thu, 24 Jun 2021 08:00:00 -0000;Thu, 17 Jun 2021 08:00:00 -0000;Thu, 10 Jun 2021 16:00:00 -0000;Thu, 03 Jun 2021 08:00:00 -0000;Thu, 27 May 2021 08:00:00 -0000;Thu, 20 May 2021 08:00:00 -0000;Tue, 11 May 2021 20:04:00 -0000
+Mon, 12 Feb 2024 08:01:00 -0000;Mon, 05 Feb 2024 08:01:00 -0000;Wed, 24 Jan 2024 16:58:39 -0000
+Sat, 17 Feb 2024 01:23:21 -0000;Fri, 16 Feb 2024 07:45:00 -0000;Wed, 31 Jan 2024 05:00:00 -0000;Mon, 22 Jan 2024 17:00:00 -0000;Wed, 17 Jan 2024 08:01:00 -0000;Fri, 29 Dec 2023 08:02:00 -0000;Fri, 22 Dec 2023 08:02:00 -0000;Fri, 15 Dec 2023 08:02:00 -0000;Fri, 08 Dec 2023 08:02:00 -0000;Fri, 01 Dec 2023 08:05:00 -0000;Fri, 01 Dec 2023 08:02:00 -0000;Mon, 27 Nov 2023 22:16:00 -0000;Wed, 25 Oct 2023 20:21:00 -0000;Fri, 05 May 2023 12:30:00 -0000;Fri, 27 May 2022 02:36:00 -0000;Wed, 25 May 2022 01:47:00 -0000;Fri, 20 May 2022 16:31:00 -0000;Fri, 20 May 2022 05:15:00 -0000;Thu, 19 May 2022 07:01:00 -0000;Wed, 18 May 2022 01:50:00 -0000;Fri, 13 May 2022 02:53:00 -0000;Wed, 11 May 2022 15:00:00 -0000;Thu, 05 May 2022 04:01:00 -0000;Tue, 03 May 2022 02:36:00 -0000;Sun, 01 May 2022 04:00:00 -0000;Wed, 24 Nov 2021 09:45:00 -0000;Wed, 17 Nov 2021 08:00:00 -0000;Wed, 10 Nov 2021 08:00:00 -0000;Thu, 04 Nov 2021 03:08:00 -0000;Thu, 28 Oct 2021 07:00:00 -0000;Wed, 27 Oct 2021 07:00:00 -0000;Wed, 20 Oct 2021 02:50:00 -0000;Wed, 13 Oct 2021 04:01:00 -0000;Sat, 02 Oct 2021 02:36:00 -0000;Thu, 30 Sep 2021 00:46:10 -0000;Wed, 22 Sep 2021 04:29:00 -0000;Wed, 15 Sep 2021 00:01:49 -0000;Wed, 08 Sep 2021 04:01:00 -0000;Wed, 01 Sep 2021 07:00:00 -0000;Fri, 20 Aug 2021 20:00:00 -0000;Thu, 19 Mar 2020 04:01:00 -0000;Thu, 12 Mar 2020 12:00:00 -0000;Thu, 05 Mar 2020 18:32:00 -0000;Thu, 27 Feb 2020 04:00:00 -0000;Thu, 20 Feb 2020 15:44:00 -0000;Wed, 12 Feb 2020 22:46:00 -0000;Fri, 24 May 2019 21:02:00 -0000;Sat, 27 Apr 2019 02:47:00 -0000;Tue, 19 Mar 2019 03:39:00 -0000;Tue, 12 Mar 2019 00:30:00 -0000
+Thu, 15 Feb 2024 22:15:16 -0000;Wed, 14 Feb 2024 01:58:00 -0000
+Mon, 12 Feb 2024 15:15:00 GMT;Mon, 05 Feb 2024 14:35:12 GMT;Mon, 29 Jan 2024 14:18:05 GMT;Mon, 22 Jan 2024 14:55:00 GMT;Mon, 15 Jan 2024 15:00:00 GMT;Mon, 08 Jan 2024 14:31:36 GMT;Mon, 01 Jan 2024 15:00:00 GMT;Mon, 25 Dec 2023 14:34:02 GMT;Mon, 18 Dec 2023 18:55:00 GMT;Mon, 11 Dec 2023 22:47:19 GMT;Mon, 04 Dec 2023 15:00:00 GMT;Mon, 27 Nov 2023 15:00:00 GMT;Mon, 20 Nov 2023 15:00:00 GMT;Sun, 19 Nov 2023 23:03:21 GMT;Mon, 13 Nov 2023 15:00:00 GMT;Mon, 06 Nov 2023 15:10:00 GMT;Mon, 30 Oct 2023 14:11:00 GMT;Mon, 23 Oct 2023 14:11:00 GMT;Mon, 16 Oct 2023 14:28:08 GMT;Mon, 09 Oct 2023 16:26:15 GMT;Mon, 02 Oct 2023 14:10:00 GMT;Mon, 18 Sep 2023 15:02:57 GMT;Mon, 11 Sep 2023 14:10:00 GMT;Mon, 04 Sep 2023 15:31:04 GMT;Mon, 28 Aug 2023 14:34:31 GMT;Mon, 21 Aug 2023 14:13:00 GMT;Mon, 14 Aug 2023 14:24:44 GMT;Mon, 07 Aug 2023 14:29:49 GMT;Mon, 31 Jul 2023 14:13:00 GMT;Mon, 24 Jul 2023 14:13:00 GMT;Mon, 17 Jul 2023 14:31:20 GMT;Mon, 10 Jul 2023 14:10:01 GMT;Mon, 03 Jul 2023 14:11:00 GMT;Mon, 26 Jun 2023 14:59:42 GMT;Mon, 19 Jun 2023 14:13:34 GMT;Mon, 12 Jun 2023 14:17:11 GMT;Mon, 05 Jun 2023 14:25:34 GMT;Mon, 29 May 2023 14:37:09 GMT;Mon, 22 May 2023 14:25:15 GMT;Mon, 15 May 2023 14:25:35 GMT;Fri, 12 May 2023 14:25:55 GMT;Mon, 08 May 2023 13:54:45 GMT;Fri, 05 May 2023 15:57:04 GMT;Mon, 01 May 2023 14:35:51 GMT;Mon, 24 Apr 2023 15:09:29 GMT;Mon, 17 Apr 2023 14:40:16 GMT;Mon, 10 Apr 2023 14:30:39 GMT;Mon, 03 Apr 2023 14:30:44 GMT;Mon, 27 Mar 2023 14:30:24 GMT;Fri, 24 Mar 2023 15:00:18 GMT
+Tue, 13 Feb 2024 10:00:00 -0000;Tue, 06 Feb 2024 10:00:00 -0000;Tue, 30 Jan 2024 10:00:00 -0000;Thu, 25 Jan 2024 10:00:00 -0000;Tue, 23 Jan 2024 10:00:00 -0000;Thu, 09 Mar 2023 14:00:00 -0000;Wed, 14 Oct 2020 05:05:00 -0000;Fri, 04 Sep 2020 17:05:00 -0000;Thu, 11 Jun 2020 05:00:00 -0000;Thu, 28 May 2020 05:00:00 -0000;Thu, 21 May 2020 05:00:00 -0000;Thu, 14 May 2020 05:00:00 -0000;Wed, 06 May 2020 05:00:00 -0000;Thu, 30 Apr 2020 05:00:00 -0000;Thu, 23 Apr 2020 06:00:00 -0000;Mon, 06 Jan 2020 06:00:00 -0000;Sun, 22 Dec 2019 06:00:00 -0000;Mon, 16 Dec 2019 06:00:00 -0000;Tue, 02 Jul 2019 05:00:00 -0000;Fri, 21 Jun 2019 05:00:00 -0000;Tue, 26 Mar 2019 05:00:00 -0000;Tue, 19 Mar 2019 05:00:00 -0000;Tue, 27 Nov 2018 06:00:00 -0000;Fri, 02 Nov 2018 21:38:00 -0000;Thu, 20 Sep 2018 21:52:00 -0000;Tue, 18 Sep 2018 05:00:00 -0000;Tue, 03 Jul 2018 05:00:00 -0000;Tue, 26 Jun 2018 05:00:00 -0000;Tue, 19 Jun 2018 05:00:00 -0000;Tue, 12 Jun 2018 05:00:00 -0000;Tue, 05 Jun 2018 05:00:00 -0000;Tue, 29 May 2018 05:00:00 -0000;Tue, 22 May 2018 05:00:00 -0000;Tue, 15 May 2018 05:00:00 -0000;Tue, 08 May 2018 05:00:00 -0000;Tue, 01 May 2018 06:00:00 -0000;Tue, 01 May 2018 05:00:00 -0000;Mon, 16 Apr 2018 16:00:00 -0000;Fri, 02 Dec 2016 06:00:00 -0000;Tue, 25 Oct 2016 05:00:00 -0000;Tue, 18 Oct 2016 05:00:00 -0000;Tue, 11 Oct 2016 05:00:00 -0000;Tue, 04 Oct 2016 05:00:00 -0000;Tue, 27 Sep 2016 05:00:00 -0000;Tue, 20 Sep 2016 05:00:00 -0000;Tue, 13 Sep 2016 05:00:00 -0000;Wed, 07 Sep 2016 06:00:00 -0000;Wed, 07 Sep 2016 05:00:00 -0000;Mon, 29 Aug 2016 05:00:00 -0000
+Thu, 15 Feb 2024 08:00:00 +0000;Thu, 8 Feb 2024 08:00:00 +0000;Thu, 1 Feb 2024 08:00:00 +0000;Thu, 25 Jan 2024 08:05:00 +0000;Thu, 25 Jan 2024 08:00:00 +0000;Thu, 11 Jan 2024 15:33:41 +0000
+Sat, 17 Feb 2024 08:00:00 +0000;Fri, 16 Feb 2024 18:38:47 +0000;Thu, 15 Feb 2024 21:30:40 +0000;Wed, 14 Feb 2024 19:50:50 +0000;Tue, 13 Feb 2024 19:55:17 +0000;Mon, 12 Feb 2024 20:13:11 +0000;Sat, 10 Feb 2024 08:00:00 +0000;Fri, 09 Feb 2024 20:16:26 +0000;Thu, 08 Feb 2024 20:02:28 +0000;Wed, 07 Feb 2024 20:23:12 +0000;Tue, 06 Feb 2024 20:08:05 +0000;Mon, 05 Feb 2024 19:13:10 +0000;Sat, 03 Feb 2024 08:00:00 +0000;Fri, 02 Feb 2024 20:11:50 +0000;Thu, 01 Feb 2024 21:15:49 +0000;Wed, 31 Jan 2024 19:27:07 +0000;Tue, 30 Jan 2024 20:42:10 +0000;Mon, 29 Jan 2024 19:50:04 +0000;Sat, 27 Jan 2024 08:00:00 +0000;Fri, 26 Jan 2024 20:07:04 +0000;Thu, 25 Jan 2024 19:34:17 +0000;Wed, 24 Jan 2024 19:08:06 +0000;Tue, 23 Jan 2024 19:51:30 +0000;Mon, 22 Jan 2024 19:52:56 +0000;Sat, 20 Jan 2024 08:00:00 +0000;Fri, 19 Jan 2024 15:16:38 +0000;Thu, 18 Jan 2024 19:40:52 +0000;Wed, 17 Jan 2024 19:08:05 +0000;Tue, 16 Jan 2024 20:16:47 +0000;Mon, 15 Jan 2024 08:00:00 +0000;Sat, 13 Jan 2024 12:00:00 +0000;Fri, 12 Jan 2024 12:00:00 +0000;Thu, 11 Jan 2024 20:15:41 +0000;Wed, 10 Jan 2024 19:14:00 +0000;Tue, 09 Jan 2024 20:03:59 +0000;Mon, 08 Jan 2024 20:27:11 +0000;Sat, 06 Jan 2024 08:00:00 +0000;Fri, 05 Jan 2024 19:36:37 +0000;Thu, 04 Jan 2024 19:23:48 +0000;Wed, 03 Jan 2024 19:58:41 +0000;Tue, 02 Jan 2024 19:52:47 +0000;Mon, 01 Jan 2024 11:27:20 +0000;Sat, 30 Dec 2023 08:00:00 +0000;Fri, 29 Dec 2023 11:29:20 +0000;Thu, 28 Dec 2023 19:14:07 +0000;Wed, 27 Dec 2023 19:35:21 +0000;Tue, 26 Dec 2023 19:13:19 +0000;Mon, 25 Dec 2023 08:00:00 +0000;Sat, 23 Dec 2023 08:00:00 +0000;Fri, 22 Dec 2023 08:00:00 +0000
+Fri, 16 Feb 2024 00:10:00 -0000;Thu, 15 Feb 2024 00:10:00 -0000;Tue, 13 Feb 2024 00:10:00 -0000;Mon, 12 Feb 2024 00:10:00 -0000;Thu, 08 Feb 2024 00:10:00 -0000;Mon, 05 Feb 2024 00:10:00 -0000;Thu, 01 Feb 2024 00:10:00 -0000;Mon, 29 Jan 2024 00:10:00 -0000;Thu, 25 Jan 2024 00:10:00 -0000;Mon, 22 Jan 2024 00:10:00 -0000;Thu, 18 Jan 2024 00:10:00 -0000;Tue, 16 Jan 2024 00:20:00 -0000;Mon, 15 Jan 2024 00:10:00 -0000;Thu, 11 Jan 2024 00:10:00 -0000;Mon, 08 Jan 2024 00:10:00 -0000;Thu, 04 Jan 2024 00:10:00 -0000;Mon, 01 Jan 2024 00:10:00 -0000;Thu, 28 Dec 2023 00:10:00 -0000;Mon, 25 Dec 2023 00:10:00 -0000;Thu, 21 Dec 2023 00:10:00 -0000;Mon, 18 Dec 2023 00:10:00 -0000;Fri, 15 Dec 2023 12:16:00 -0000;Thu, 14 Dec 2023 00:10:00 -0000;Mon, 11 Dec 2023 00:05:00 -0000;Thu, 07 Dec 2023 00:05:00 -0000;Tue, 05 Dec 2023 00:05:00 -0000;Mon, 04 Dec 2023 00:05:00 -0000;Thu, 30 Nov 2023 00:05:00 -0000;Tue, 28 Nov 2023 00:05:00 -0000;Mon, 27 Nov 2023 00:05:00 -0000;Fri, 24 Nov 2023 00:05:00 -0000;Thu, 23 Nov 2023 00:05:00 -0000;Mon, 20 Nov 2023 00:05:00 -0000;Thu, 16 Nov 2023 00:05:00 -0000;Tue, 14 Nov 2023 00:05:00 -0000;Mon, 13 Nov 2023 00:05:00 -0000;Thu, 09 Nov 2023 00:05:00 -0000;Tue, 07 Nov 2023 00:05:00 -0000;Mon, 06 Nov 2023 00:05:00 -0000;Thu, 02 Nov 2023 00:00:00 -0000;Mon, 30 Oct 2023 00:00:00 -0000;Wed, 25 Oct 2023 23:00:00 -0000;Sun, 22 Oct 2023 23:05:00 -0000;Wed, 18 Oct 2023 23:00:00 -0000;Sun, 15 Oct 2023 23:00:00 -0000;Wed, 11 Oct 2023 23:05:00 -0000;Sun, 08 Oct 2023 23:30:00 -0000;Wed, 04 Oct 2023 23:00:00 -0000;Sun, 01 Oct 2023 23:00:00 -0000;Wed, 27 Sep 2023 23:00:00 -0000
+Thu, 15 Feb 2024 08:00:00 -0000;Mon, 12 Feb 2024 23:33:00 -0000;Thu, 08 Feb 2024 08:00:00 -0000;Thu, 01 Feb 2024 02:47:39 -0000;Thu, 25 Jan 2024 08:00:00 -0000;Tue, 23 Jan 2024 13:00:00 -0000;Thu, 18 Jan 2024 08:00:00 -0000;Thu, 11 Jan 2024 08:00:00 -0000;Thu, 04 Jan 2024 08:00:00 -0000;Thu, 28 Dec 2023 08:00:00 -0000;Thu, 21 Dec 2023 08:00:00 -0000;Thu, 14 Dec 2023 08:00:00 -0000;Thu, 07 Dec 2023 08:00:00 -0000;Thu, 30 Nov 2023 01:23:22 -0000;Wed, 22 Nov 2023 19:31:11 -0000;Thu, 16 Nov 2023 08:00:00 -0000;Thu, 09 Nov 2023 08:00:00 -0000;Thu, 02 Nov 2023 07:00:00 -0000;Thu, 26 Oct 2023 07:00:00 -0000;Thu, 19 Oct 2023 03:43:13 -0000;Thu, 12 Oct 2023 07:00:00 -0000;Thu, 05 Oct 2023 07:00:00 -0000;Thu, 28 Sep 2023 07:00:00 -0000;Thu, 21 Sep 2023 07:00:00 -0000;Thu, 14 Sep 2023 07:00:00 -0000;Tue, 12 Sep 2023 19:11:39 -0000;Thu, 07 Sep 2023 07:00:00 -0000;Thu, 31 Aug 2023 06:00:00 -0000;Thu, 24 Aug 2023 07:00:00 -0000;Thu, 17 Aug 2023 07:00:00 -0000;Thu, 10 Aug 2023 07:00:00 -0000;Thu, 03 Aug 2023 07:00:00 -0000;Thu, 27 Jul 2023 07:00:00 -0000;Thu, 20 Jul 2023 07:00:00 -0000;Thu, 13 Jul 2023 07:00:00 -0000;Thu, 06 Jul 2023 07:00:00 -0000;Thu, 29 Jun 2023 07:03:00 -0000;Thu, 22 Jun 2023 07:00:00 -0000;Thu, 15 Jun 2023 07:01:00 -0000;Thu, 08 Jun 2023 07:00:00 -0000;Thu, 01 Jun 2023 07:00:00 -0000;Thu, 25 May 2023 07:00:00 -0000;Thu, 18 May 2023 07:00:00 -0000;Thu, 11 May 2023 07:00:00 -0000;Thu, 04 May 2023 07:00:00 -0000;Thu, 27 Apr 2023 07:00:00 -0000;Thu, 20 Apr 2023 07:00:00 -0000;Thu, 13 Apr 2023 07:00:00 -0000;Thu, 06 Apr 2023 07:00:00 -0000;Thu, 30 Mar 2023 07:01:00 -0000
+Tue, 13 Feb 2024 20:47:30 GMT;Tue, 06 Feb 2024 17:10:10 GMT;Tue, 30 Jan 2024 14:37:32 GMT;Tue, 23 Jan 2024 17:43:45 GMT;Tue, 16 Jan 2024 16:45:53 GMT;Tue, 09 Jan 2024 18:14:00 GMT;Tue, 02 Jan 2024 19:37:32 GMT;Tue, 19 Dec 2023 20:53:25 GMT;Tue, 12 Dec 2023 16:34:31 GMT;Tue, 05 Dec 2023 14:53:01 GMT;Tue, 28 Nov 2023 14:21:49 GMT;Tue, 21 Nov 2023 18:21:14 GMT;Tue, 14 Nov 2023 17:07:00 GMT;Wed, 08 Nov 2023 00:26:03 GMT;Tue, 31 Oct 2023 16:01:50 GMT;Tue, 24 Oct 2023 19:46:10 GMT;Tue, 17 Oct 2023 18:02:58 GMT;Tue, 10 Oct 2023 17:17:26 GMT;Tue, 03 Oct 2023 17:53:56 GMT;Tue, 26 Sep 2023 18:54:12 GMT;Tue, 19 Sep 2023 16:03:30 GMT;Wed, 13 Sep 2023 02:05:47 GMT;Wed, 06 Sep 2023 03:17:40 GMT;Tue, 29 Aug 2023 22:05:28 GMT;Tue, 22 Aug 2023 23:26:56 GMT;Wed, 16 Aug 2023 15:57:56 GMT;Wed, 09 Aug 2023 00:11:02 GMT;Wed, 02 Aug 2023 15:16:44 GMT;Wed, 26 Jul 2023 01:25:58 GMT;Tue, 18 Jul 2023 17:04:17 GMT;Wed, 12 Jul 2023 16:04:36 GMT;Tue, 04 Jul 2023 22:20:24 GMT;Tue, 27 Jun 2023 13:20:17 GMT;Tue, 20 Jun 2023 04:36:27 GMT;Tue, 13 Jun 2023 14:50:46 GMT;Tue, 30 May 2023 22:46:25 GMT;Mon, 22 May 2023 23:46:24 GMT;Wed, 17 May 2023 15:24:05 GMT;Wed, 10 May 2023 13:46:32 GMT;Tue, 02 May 2023 20:38:58 GMT;Tue, 25 Apr 2023 16:54:12 GMT;Wed, 19 Apr 2023 02:22:12 GMT;Wed, 12 Apr 2023 04:09:06 GMT;Tue, 04 Apr 2023 13:43:25 GMT;Tue, 28 Mar 2023 13:59:28 GMT;Wed, 22 Mar 2023 03:52:15 GMT;Tue, 14 Mar 2023 20:04:15 GMT;Tue, 07 Mar 2023 02:27:36 GMT;Tue, 28 Feb 2023 18:08:15 GMT;Tue, 21 Feb 2023 19:38:23 GMT
+Fri, 16 Feb 2024 05:00:00 -0000;Tue, 13 Feb 2024 22:32:00 -0000;Mon, 12 Feb 2024 06:48:00 -0000;Thu, 08 Feb 2024 22:01:00 -0000;Thu, 08 Feb 2024 18:59:00 -0000;Wed, 07 Feb 2024 05:00:00 -0000;Mon, 05 Feb 2024 06:38:00 -0000;Wed, 31 Jan 2024 05:00:00 -0000;Mon, 29 Jan 2024 05:33:00 -0000;Fri, 26 Jan 2024 07:19:00 -0000;Wed, 24 Jan 2024 05:00:00 -0000;Mon, 22 Jan 2024 05:18:00 -0000;Thu, 18 Jan 2024 22:21:00 -0000;Tue, 16 Jan 2024 06:14:00 -0000;Mon, 15 Jan 2024 06:24:00 -0000;Fri, 12 Jan 2024 06:43:00 -0000;Thu, 11 Jan 2024 23:28:00 -0000;Tue, 09 Jan 2024 20:38:00 -0000;Mon, 08 Jan 2024 07:16:00 -0000;Fri, 05 Jan 2024 05:00:00 -0000;Wed, 03 Jan 2024 20:06:00 -0000;Mon, 01 Jan 2024 20:47:00 -0000;Thu, 28 Dec 2023 21:42:00 -0000;Tue, 26 Dec 2023 07:02:00 -0000;Fri, 22 Dec 2023 08:00:00 -0000;Tue, 19 Dec 2023 20:14:00 -0000;Mon, 18 Dec 2023 07:15:00 -0000;Fri, 15 Dec 2023 07:35:00 -0000;Tue, 12 Dec 2023 20:02:00 -0000;Mon, 11 Dec 2023 07:13:00 -0000;Fri, 08 Dec 2023 06:44:00 -0000;Mon, 04 Dec 2023 08:34:00 -0000;Fri, 01 Dec 2023 06:51:00 -0000;Wed, 29 Nov 2023 08:03:00 -0000;Mon, 27 Nov 2023 07:17:27 -0000;Wed, 22 Nov 2023 06:40:20 -0000;Tue, 21 Nov 2023 23:38:25 -0000;Mon, 20 Nov 2023 07:11:32 -0000;Fri, 17 Nov 2023 05:59:32 -0000;Tue, 14 Nov 2023 21:59:28 -0000;Mon, 13 Nov 2023 07:08:36 -0000;Fri, 10 Nov 2023 05:00:00 -0000;Wed, 08 Nov 2023 04:32:06 -0000;Mon, 06 Nov 2023 07:11:37 -0000;Fri, 03 Nov 2023 04:00:00 -0000;Wed, 01 Nov 2023 00:28:15 -0000;Mon, 30 Oct 2023 06:50:00 -0000;Fri, 27 Oct 2023 06:26:25 -0000;Wed, 25 Oct 2023 06:02:00 -0000;Mon, 23 Oct 2023 06:34:00 -0000
+Tue, 06 Feb 2024 12:00:00 +0000;Tue, 23 Jan 2024 11:00:00 +0000;Tue, 16 Jan 2024 09:16:00 +0000
+Fri, 16 Feb 2024 09:00:00 -0000;Mon, 12 Feb 2024 09:00:00 -0000;Fri, 09 Feb 2024 09:00:00 -0000;Mon, 05 Feb 2024 09:00:00 -0000;Fri, 02 Feb 2024 09:00:00 -0000;Mon, 29 Jan 2024 09:00:00 -0000;Fri, 26 Jan 2024 09:00:00 -0000;Mon, 22 Jan 2024 09:00:00 -0000;Fri, 19 Jan 2024 09:00:00 -0000;Mon, 15 Jan 2024 09:00:00 -0000;Fri, 12 Jan 2024 09:00:00 -0000;Mon, 08 Jan 2024 09:00:00 -0000;Fri, 05 Jan 2024 09:00:00 -0000;Mon, 01 Jan 2024 09:00:00 -0000;Fri, 29 Dec 2023 09:00:00 -0000;Mon, 25 Dec 2023 09:00:00 -0000;Fri, 22 Dec 2023 09:00:00 -0000;Mon, 18 Dec 2023 09:00:00 -0000;Fri, 15 Dec 2023 09:00:00 -0000;Mon, 11 Dec 2023 09:00:00 -0000;Fri, 08 Dec 2023 09:00:00 -0000;Mon, 04 Dec 2023 09:00:00 -0000;Fri, 01 Dec 2023 09:00:00 -0000;Mon, 27 Nov 2023 09:00:00 -0000;Fri, 24 Nov 2023 09:00:00 -0000;Mon, 20 Nov 2023 09:00:00 -0000;Fri, 17 Nov 2023 09:00:00 -0000;Mon, 13 Nov 2023 09:00:00 -0000;Fri, 10 Nov 2023 09:00:00 -0000;Mon, 06 Nov 2023 09:00:00 -0000;Fri, 03 Nov 2023 08:00:00 -0000;Mon, 30 Oct 2023 08:00:00 -0000;Fri, 27 Oct 2023 08:00:00 -0000;Mon, 23 Oct 2023 08:00:00 -0000;Fri, 20 Oct 2023 08:00:00 -0000;Mon, 16 Oct 2023 08:00:00 -0000;Fri, 13 Oct 2023 08:00:00 -0000;Mon, 09 Oct 2023 08:00:00 -0000;Fri, 06 Oct 2023 08:00:00 -0000;Mon, 02 Oct 2023 08:00:00 -0000;Fri, 29 Sep 2023 08:00:00 -0000;Mon, 25 Sep 2023 08:00:00 -0000;Fri, 22 Sep 2023 08:00:00 -0000;Mon, 18 Sep 2023 08:00:00 -0000;Fri, 15 Sep 2023 08:00:00 -0000;Mon, 11 Sep 2023 08:00:00 -0000;Fri, 08 Sep 2023 08:00:00 -0000;Mon, 04 Sep 2023 08:00:00 -0000;Fri, 01 Sep 2023 08:00:00 -0000;Mon, 28 Aug 2023 08:00:00 -0000
+Fri, 16 Feb 2024 08:30:00 -0000;Thu, 15 Feb 2024 08:30:00 -0000;Wed, 14 Feb 2024 08:30:00 -0000;Tue, 13 Feb 2024 08:30:00 -0000;Mon, 12 Feb 2024 08:30:00 -0000;Fri, 09 Feb 2024 08:30:00 -0000;Thu, 08 Feb 2024 08:30:00 -0000;Wed, 07 Feb 2024 08:30:00 -0000;Tue, 06 Feb 2024 08:30:00 -0000;Mon, 05 Feb 2024 08:30:00 -0000;Fri, 02 Feb 2024 08:30:00 -0000;Thu, 01 Feb 2024 08:30:00 -0000;Wed, 31 Jan 2024 08:30:00 -0000;Tue, 30 Jan 2024 08:30:00 -0000;Mon, 29 Jan 2024 08:30:00 -0000;Fri, 26 Jan 2024 08:30:00 -0000;Thu, 25 Jan 2024 08:30:00 -0000;Wed, 24 Jan 2024 08:30:00 -0000;Mon, 22 Jan 2024 08:30:00 -0000;Fri, 19 Jan 2024 08:30:00 -0000;Thu, 18 Jan 2024 08:30:00 -0000;Wed, 17 Jan 2024 08:30:00 -0000;Mon, 15 Jan 2024 08:30:00 -0000;Fri, 12 Jan 2024 08:30:00 -0000;Thu, 11 Jan 2024 08:30:00 -0000;Wed, 10 Jan 2024 08:30:00 -0000;Mon, 08 Jan 2024 08:30:00 -0000;Fri, 05 Jan 2024 08:30:00 -0000;Thu, 04 Jan 2024 08:30:00 -0000;Wed, 03 Jan 2024 08:30:00 -0000;Mon, 01 Jan 2024 08:30:00 -0000;Fri, 29 Dec 2023 08:20:00 -0000;Fri, 22 Dec 2023 08:30:00 -0000;Fri, 22 Dec 2023 08:20:00 -0000;Thu, 21 Dec 2023 08:30:00 -0000;Wed, 20 Dec 2023 08:30:00 -0000;Tue, 19 Dec 2023 08:30:00 -0000;Mon, 18 Dec 2023 08:30:00 -0000;Fri, 15 Dec 2023 08:30:00 -0000;Fri, 15 Dec 2023 08:20:00 -0000;Thu, 14 Dec 2023 08:30:00 -0000;Wed, 13 Dec 2023 08:30:00 -0000;Tue, 12 Dec 2023 08:30:00 -0000;Mon, 11 Dec 2023 08:30:00 -0000;Fri, 08 Dec 2023 08:30:00 -0000;Fri, 08 Dec 2023 08:20:00 -0000;Thu, 07 Dec 2023 08:30:00 -0000;Wed, 06 Dec 2023 08:30:00 -0000;Tue, 05 Dec 2023 08:30:00 -0000;Mon, 04 Dec 2023 08:30:00 -0000
+Sat, 17 Feb 2024 14:35:48 +0000;Sat, 10 Feb 2024 15:35:53 +0000;Sat, 03 Feb 2024 13:46:54 +0000;Sat, 27 Jan 2024 08:00:59 +0000;Sat, 20 Jan 2024 08:00:59 +0000;Sat, 13 Jan 2024 14:48:33 +0000;Sat, 06 Jan 2024 08:00:59 +0000;Sat, 30 Dec 2023 08:00:00 +0000;Sat, 23 Dec 2023 08:00:59 +0000;Tue, 19 Dec 2023 00:08:23 +0000;Sat, 16 Dec 2023 14:48:46 +0000;Mon, 11 Dec 2023 21:19:00 +0000;Sat, 09 Dec 2023 10:37:57 +0000;Sat, 02 Dec 2023 14:13:46 +0000;Sat, 25 Nov 2023 08:00:59 +0000;Sat, 18 Nov 2023 17:00:29 +0000;Sat, 11 Nov 2023 08:00:59 +0000;Sat, 04 Nov 2023 12:47:27 +0000;Sat, 28 Oct 2023 12:31:22 +0000;Sat, 21 Oct 2023 16:23:13 +0000;Sat, 14 Oct 2023 12:02:50 +0000;Sat, 07 Oct 2023 14:45:14 +0000;Sat, 30 Sep 2023 16:03:57 +0000;Sat, 23 Sep 2023 16:00:59 +0000;Sat, 16 Sep 2023 16:00:18 +0000;Sat, 09 Sep 2023 15:50:47 +0000;Sat, 02 Sep 2023 16:00:37 +0000;Sat, 26 Aug 2023 16:00:53 +0000;Sat, 19 Aug 2023 16:00:00 +0000;Sat, 12 Aug 2023 16:00:46 +0000;Sat, 05 Aug 2023 16:00:11 +0000;Sat, 29 Jul 2023 16:00:56 +0000;Sat, 22 Jul 2023 16:00:11 +0000;Sat, 15 Jul 2023 16:00:04 +0000;Sat, 08 Jul 2023 16:00:00 +0000;Sat, 01 Jul 2023 16:00:55 +0000;Sat, 24 Jun 2023 16:00:02 +0000;Sat, 17 Jun 2023 16:00:32 +0000;Sat, 10 Jun 2023 16:00:45 +0000;Sat, 03 Jun 2023 16:00:07 +0000;Sat, 27 May 2023 16:00:04 +0000;Sat, 20 May 2023 16:00:08 +0000;Sat, 13 May 2023 16:00:57 +0000;Sat, 06 May 2023 15:55:33 +0000;Sat, 29 Apr 2023 16:04:28 +0000;Sat, 22 Apr 2023 16:00:09 +0000;Sat, 15 Apr 2023 16:00:26 +0000;Wed, 12 Apr 2023 14:00:16 +0000;Sat, 08 Apr 2023 15:55:22 +0000;Sat, 01 Apr 2023 16:01:14 +0000
+Wed, 14 Feb 2024 08:01:00 -0000;Wed, 07 Feb 2024 08:01:00 -0000;Wed, 31 Jan 2024 08:01:00 -0000;Wed, 24 Jan 2024 08:01:00 -0000;Wed, 17 Jan 2024 08:01:00 -0000;Wed, 10 Jan 2024 08:01:00 -0000;Wed, 03 Jan 2024 08:01:00 -0000;Wed, 27 Dec 2023 08:01:00 -0000;Wed, 20 Dec 2023 08:01:00 -0000;Wed, 13 Dec 2023 08:01:00 -0000;Wed, 06 Dec 2023 08:01:00 -0000;Wed, 29 Nov 2023 08:01:00 -0000;Wed, 22 Nov 2023 08:01:00 -0000;Wed, 15 Nov 2023 08:01:00 -0000;Wed, 08 Nov 2023 08:01:00 -0000;Wed, 01 Nov 2023 07:01:00 -0000;Wed, 25 Oct 2023 07:01:00 -0000;Wed, 18 Oct 2023 07:01:00 -0000;Wed, 11 Oct 2023 07:01:00 -0000;Wed, 04 Oct 2023 21:00:00 -0000
+Fri, 16 Feb 2024 17:00:00 -0000;Mon, 12 Feb 2024 18:25:00 -0000;Mon, 05 Feb 2024 09:00:00 -0000;Tue, 30 Jan 2024 18:31:00 -0000;Mon, 22 Jan 2024 09:00:00 -0000;Mon, 15 Jan 2024 15:32:00 -0000;Mon, 08 Jan 2024 09:00:00 -0000;Mon, 01 Jan 2024 09:00:00 -0000;Mon, 25 Dec 2023 09:00:00 -0000;Mon, 18 Dec 2023 09:00:00 -0000;Mon, 11 Dec 2023 09:00:00 -0000;Mon, 04 Dec 2023 09:00:00 -0000;Mon, 27 Nov 2023 09:00:00 -0000;Mon, 20 Nov 2023 09:00:00 -0000;Mon, 13 Nov 2023 09:00:00 -0000;Mon, 06 Nov 2023 09:00:00 -0000;Mon, 30 Oct 2023 08:00:00 -0000;Mon, 23 Oct 2023 08:00:00 -0000;Mon, 16 Oct 2023 08:00:00 -0000;Mon, 09 Oct 2023 08:00:00 -0000;Mon, 02 Oct 2023 08:00:00 -0000;Mon, 25 Sep 2023 08:00:00 -0000;Mon, 18 Sep 2023 08:00:00 -0000;Mon, 11 Sep 2023 08:00:00 -0000;Mon, 04 Sep 2023 08:00:00 -0000;Mon, 28 Aug 2023 08:00:00 -0000;Mon, 21 Aug 2023 08:00:00 -0000;Mon, 14 Aug 2023 08:00:00 -0000;Mon, 07 Aug 2023 07:05:00 -0000;Mon, 31 Jul 2023 07:15:00 -0000;Mon, 24 Jul 2023 08:00:00 -0000;Mon, 17 Jul 2023 08:00:00 -0000;Mon, 10 Jul 2023 08:00:00 -0000;Mon, 03 Jul 2023 08:00:00 -0000;Mon, 26 Jun 2023 08:00:00 -0000;Mon, 19 Jun 2023 08:00:00 -0000;Mon, 12 Jun 2023 07:05:00 -0000;Mon, 05 Jun 2023 08:00:00 -0000;Mon, 29 May 2023 08:00:00 -0000;Mon, 22 May 2023 08:00:00 -0000;Mon, 15 May 2023 08:00:00 -0000;Mon, 08 May 2023 08:00:00 -0000;Mon, 01 May 2023 08:00:00 -0000;Mon, 24 Apr 2023 08:00:00 -0000;Mon, 17 Apr 2023 08:00:00 -0000;Mon, 10 Apr 2023 08:00:00 -0000;Mon, 03 Apr 2023 08:00:00 -0000;Mon, 27 Mar 2023 08:00:00 -0000;Mon, 20 Mar 2023 08:00:00 -0000;Mon, 13 Mar 2023 07:05:00 -0000
+Fri, 16 Feb 2024 06:36:27 +0000;Fri, 16 Feb 2024 06:35:00 +0000;Thu, 15 Feb 2024 18:40:17 +0000;Wed, 14 Feb 2024 05:01:00 +0000;Wed, 14 Feb 2024 05:01:00 +0000;Tue, 13 Feb 2024 07:03:40 +0000;Tue, 13 Feb 2024 06:56:25 +0000;Mon, 12 Feb 2024 18:11:11 +0000;Mon, 12 Feb 2024 08:21:41 +0000;Mon, 12 Feb 2024 08:19:09 +0000;Sat, 10 Feb 2024 00:40:00 +0000;Sat, 10 Feb 2024 00:31:29 +0000;Thu, 08 Feb 2024 17:47:34 +0000;Wed, 07 Feb 2024 05:01:00 +0000;Wed, 07 Feb 2024 05:01:00 +0000;Tue, 06 Feb 2024 06:20:00 +0000;Tue, 06 Feb 2024 06:09:29 +0000;Mon, 05 Feb 2024 07:17:22 +0000;Mon, 05 Feb 2024 07:13:37 +0000;Sun, 04 Feb 2024 23:08:24 +0000;Sat, 03 Feb 2024 20:17:52 +0000;Fri, 02 Feb 2024 07:20:00 +0000;Fri, 02 Feb 2024 07:16:47 +0000;Thu, 01 Feb 2024 17:07:53 +0000;Thu, 01 Feb 2024 08:52:39 +0000;Thu, 01 Feb 2024 07:52:27 +0000;Wed, 31 Jan 2024 05:01:00 +0000;Tue, 30 Jan 2024 06:42:12 +0000;Mon, 29 Jan 2024 16:59:07 +0000;Mon, 29 Jan 2024 06:40:00 +0000;Fri, 26 Jan 2024 06:41:09 +0000;Thu, 25 Jan 2024 17:39:12 +0000;Thu, 25 Jan 2024 08:49:19 +0000;Wed, 24 Jan 2024 05:01:00 +0000;Wed, 24 Jan 2024 05:01:00 +0000;Tue, 23 Jan 2024 06:50:47 +0000;Mon, 22 Jan 2024 18:03:15 +0000;Mon, 22 Jan 2024 06:49:31 +0000;Sun, 21 Jan 2024 08:00:17 +0000;Fri, 19 Jan 2024 17:52:39 +0000;Fri, 19 Jan 2024 08:04:02 +0000;Thu, 18 Jan 2024 17:21:18 +0000;Thu, 18 Jan 2024 08:56:18 +0000;Wed, 17 Jan 2024 05:01:00 +0000;Wed, 17 Jan 2024 05:01:00 +0000;Tue, 16 Jan 2024 07:26:50 +0000;Mon, 15 Jan 2024 19:14:01 +0000;Mon, 15 Jan 2024 07:38:45 +0000;Sun, 14 Jan 2024 07:39:28 +0000;Fri, 12 Jan 2024 07:55:40 +0000
+Thu, 15 Feb 2024 08:01:00 +0000;Tue, 13 Feb 2024 08:01:00 +0000;Mon, 12 Feb 2024 08:01:00 +0000;Thu, 08 Feb 2024 08:01:00 +0000;Tue, 06 Feb 2024 08:01:00 +0000;Mon, 05 Feb 2024 08:01:00 +0000;Thu, 01 Feb 2024 08:01:00 +0000;Tue, 30 Jan 2024 08:01:00 +0000;Mon, 29 Jan 2024 08:01:00 +0000;Fri, 26 Jan 2024 08:01:00 +0000;Thu, 25 Jan 2024 08:01:00 +0000;Tue, 23 Jan 2024 08:01:00 +0000;Mon, 22 Jan 2024 08:01:00 +0000;Thu, 18 Jan 2024 08:01:00 +0000;Tue, 16 Jan 2024 08:01:00 +0000;Mon, 15 Jan 2024 08:01:00 +0000;Thu, 11 Jan 2024 08:01:00 +0000;Tue, 09 Jan 2024 08:01:00 +0000;Mon, 08 Jan 2024 08:01:00 +0000;Thu, 04 Jan 2024 08:01:00 +0000;Wed, 03 Jan 2024 08:01:00 +0000;Tue, 02 Jan 2024 08:01:00 +0000;Fri, 29 Dec 2023 08:01:00 +0000;Tue, 26 Dec 2023 08:01:00 +0000;Thu, 21 Dec 2023 08:01:00 +0000;Tue, 19 Dec 2023 08:01:00 +0000;Mon, 18 Dec 2023 08:01:00 +0000;Thu, 14 Dec 2023 08:01:00 +0000;Tue, 12 Dec 2023 08:01:00 +0000;Mon, 11 Dec 2023 08:01:00 +0000;Thu, 07 Dec 2023 08:01:00 +0000;Tue, 05 Dec 2023 08:01:00 +0000;Mon, 04 Dec 2023 08:01:00 +0000;Fri, 01 Dec 2023 08:01:00 +0000;Thu, 30 Nov 2023 08:01:00 +0000;Tue, 28 Nov 2023 08:01:00 +0000;Mon, 27 Nov 2023 08:01:00 +0000;Tue, 21 Nov 2023 08:01:00 +0000;Mon, 20 Nov 2023 08:01:00 +0000;Thu, 16 Nov 2023 08:01:00 +0000;Tue, 14 Nov 2023 08:01:00 +0000;Mon, 13 Nov 2023 08:01:00 +0000;Wed, 08 Nov 2023 08:01:00 +0000;Tue, 07 Nov 2023 08:01:00 +0000;Mon, 06 Nov 2023 07:01:00 +0000;Thu, 02 Nov 2023 07:01:00 +0000;Tue, 31 Oct 2023 07:01:00 +0000;Mon, 30 Oct 2023 07:01:00 +0000;Fri, 27 Oct 2023 07:01:00 +0000;Thu, 26 Oct 2023 07:01:00 +0000
+Thu, 15 Feb 2024 22:00:00 +0000;Mon, 12 Feb 2024 22:00:00 +0000;Thu, 8 Feb 2024 22:00:00 +0000;Mon, 5 Feb 2024 22:00:00 +0000;Thu, 1 Feb 2024 22:00:00 +0000;Mon, 29 Jan 2024 22:00:00 +0000;Thu, 25 Jan 2024 22:00:00 +0000;Tue, 23 Jan 2024 22:35:08 +0000;Mon, 22 Jan 2024 22:46:50 +0000;Thu, 18 Jan 2024 22:00:00 +0000;Mon, 15 Jan 2024 22:00:00 +0000;Thu, 11 Jan 2024 22:00:00 +0000;Mon, 8 Jan 2024 22:00:00 +0000;Thu, 4 Jan 2024 22:00:00 +0000;Mon, 1 Jan 2024 22:00:00 +0000;Thu, 28 Dec 2023 23:00:00 +0000;Mon, 25 Dec 2023 22:12:14 +0000;Thu, 21 Dec 2023 22:00:00 +0000;Mon, 18 Dec 2023 22:21:36 +0000;Thu, 14 Dec 2023 22:07:20 +0000;Mon, 11 Dec 2023 22:00:00 +0000;Thu, 7 Dec 2023 22:00:00 +0000;Mon, 4 Dec 2023 22:00:00 +0000;Thu, 30 Nov 2023 22:00:00 +0000;Mon, 27 Nov 2023 22:00:00 +0000;Thu, 23 Nov 2023 22:00:03 +0000;Mon, 20 Nov 2023 22:00:00 +0000;Thu, 16 Nov 2023 22:00:00 +0000;Mon, 13 Nov 2023 22:00:00 +0000;Thu, 9 Nov 2023 22:00:00 +0000;Mon, 6 Nov 2023 22:40:39 +0000;Thu, 2 Nov 2023 21:00:28 +0000;Mon, 30 Oct 2023 21:00:00 +0000;Thu, 26 Oct 2023 21:00:00 +0000;Mon, 23 Oct 2023 21:00:00 +0000;Thu, 19 Oct 2023 21:00:00 +0000;Mon, 16 Oct 2023 21:00:00 +0000;Thu, 12 Oct 2023 21:02:59 +0000;Thu, 5 Oct 2023 21:38:28 +0000;Thu, 28 Sep 2023 21:31:39 +0000;Thu, 21 Sep 2023 21:00:00 +0000;Thu, 14 Sep 2023 22:26:51 +0000;Thu, 7 Sep 2023 22:55:45 +0000;Thu, 31 Aug 2023 15:10:24 +0000;Thu, 24 Aug 2023 21:58:10 +0000;Thu, 17 Aug 2023 15:00:00 +0000;Thu, 10 Aug 2023 15:00:46 +0000;Thu, 3 Aug 2023 15:00:00 +0000;Thu, 27 Jul 2023 15:00:00 +0000;Thu, 20 Jul 2023 15:00:00 +0000
+Wed, 14 Feb 2024 11:00:00 -0000;Wed, 07 Feb 2024 11:00:00 -0000;Wed, 31 Jan 2024 11:00:00 -0000;Wed, 24 Jan 2024 11:00:00 -0000;Wed, 17 Jan 2024 11:00:00 -0000;Wed, 10 Jan 2024 17:00:00 -0000;Wed, 03 Jan 2024 11:00:00 -0000;Wed, 06 Dec 2023 15:31:07 -0000;Wed, 29 Nov 2023 15:04:06 -0000;Wed, 22 Nov 2023 11:00:00 -0000;Wed, 15 Nov 2023 11:00:00 -0000;Wed, 08 Nov 2023 11:00:00 -0000;Wed, 01 Nov 2023 10:00:00 -0000;Wed, 25 Oct 2023 10:00:00 -0000;Wed, 18 Oct 2023 10:00:00 -0000;Wed, 11 Oct 2023 10:00:00 -0000;Wed, 04 Oct 2023 07:00:00 -0000;Wed, 27 Sep 2023 10:00:00 -0000;Wed, 20 Sep 2023 12:00:00 -0000;Wed, 13 Sep 2023 07:00:00 -0000;Wed, 06 Sep 2023 10:00:00 -0000;Wed, 30 Aug 2023 10:00:00 -0000;Wed, 23 Aug 2023 10:00:00 -0000;Wed, 16 Aug 2023 10:00:00 -0000;Wed, 09 Aug 2023 10:00:00 -0000;Wed, 02 Aug 2023 10:00:00 -0000;Wed, 26 Jul 2023 10:00:00 -0000;Wed, 19 Jul 2023 10:00:00 -0000;Wed, 12 Jul 2023 10:00:00 -0000;Wed, 05 Jul 2023 10:00:00 -0000;Wed, 31 May 2023 08:00:00 -0000;Wed, 24 May 2023 08:00:00 -0000;Wed, 17 May 2023 08:00:00 -0000;Wed, 10 May 2023 08:00:00 -0000;Wed, 03 May 2023 08:00:00 -0000;Wed, 26 Apr 2023 08:00:00 -0000;Wed, 19 Apr 2023 08:00:00 -0000;Wed, 12 Apr 2023 08:00:00 -0000;Wed, 05 Apr 2023 08:00:00 -0000;Wed, 29 Mar 2023 08:00:00 -0000;Wed, 22 Mar 2023 08:00:00 -0000;Wed, 15 Mar 2023 08:00:00 -0000;Wed, 08 Mar 2023 09:00:00 -0000;Wed, 01 Mar 2023 09:00:00 -0000;Wed, 22 Feb 2023 09:00:00 -0000;Wed, 15 Feb 2023 12:00:00 -0000;Wed, 08 Feb 2023 12:00:00 -0000;Wed, 01 Feb 2023 09:00:00 -0000;Wed, 25 Jan 2023 09:00:00 -0000;Wed, 18 Jan 2023 09:00:00 -0000
+Sun, 18 Feb 2024 09:30:00 +0000;Sat, 17 Feb 2024 21:30:00 +0000;Sat, 17 Feb 2024 09:30:00 +0000;Fri, 16 Feb 2024 22:30:00 +0000;Fri, 16 Feb 2024 09:30:00 +0000;Thu, 15 Feb 2024 21:29:07 +0000;Thu, 15 Feb 2024 09:30:00 +0000;Wed, 14 Feb 2024 21:35:14 +0000;Wed, 14 Feb 2024 20:52:20 +0000;Wed, 14 Feb 2024 09:30:00 +0000;Tue, 13 Feb 2024 09:30:00 +0000;Mon, 12 Feb 2024 21:30:00 +0000;Mon, 12 Feb 2024 09:30:00 +0000;Sun, 11 Feb 2024 21:30:00 +0000;Sun, 11 Feb 2024 09:30:00 +0000;Sat, 10 Feb 2024 21:30:00 +0000;Sat, 10 Feb 2024 09:30:00 +0000;Fri, 9 Feb 2024 21:30:00 +0000;Fri, 9 Feb 2024 09:30:00 +0000;Thu, 8 Feb 2024 21:39:42 +0000;Thu, 8 Feb 2024 09:30:00 +0000;Wed, 7 Feb 2024 22:22:08 +0000;Wed, 7 Feb 2024 09:30:00 +0000;Tue, 6 Feb 2024 21:15:45 +0000;Tue, 6 Feb 2024 09:30:00 +0000;Mon, 5 Feb 2024 21:43:15 +0000;Mon, 5 Feb 2024 09:30:00 +0000;Sun, 4 Feb 2024 21:30:00 +0000;Sun, 4 Feb 2024 09:30:00 +0000;Sat, 3 Feb 2024 21:30:00 +0000;Sat, 3 Feb 2024 09:26:43 +0000;Fri, 2 Feb 2024 21:30:00 +0000;Fri, 2 Feb 2024 09:30:00 +0000;Thu, 1 Feb 2024 21:52:50 +0000;Thu, 1 Feb 2024 09:30:00 +0000;Wed, 31 Jan 2024 21:13:49 +0000;Wed, 31 Jan 2024 09:30:00 +0000;Tue, 30 Jan 2024 21:02:36 +0000;Tue, 30 Jan 2024 09:30:00 +0000;Mon, 29 Jan 2024 21:12:06 +0000;Mon, 29 Jan 2024 09:30:00 +0000;Sun, 28 Jan 2024 21:30:00 +0000;Sun, 28 Jan 2024 09:30:00 +0000;Sat, 27 Jan 2024 21:30:00 +0000;Sat, 27 Jan 2024 09:30:00 +0000;Fri, 26 Jan 2024 21:30:00 +0000;Fri, 26 Jan 2024 09:30:00 +0000;Thu, 25 Jan 2024 21:34:26 +0000;Thu, 25 Jan 2024 09:30:00 +0000;Wed, 24 Jan 2024 21:45:30 +0000
+Mon, 12 Feb 2024 21:00:00 +0000;Mon, 5 Feb 2024 20:00:00 +0000;Mon, 29 Jan 2024 15:00:00 +0000;Mon, 22 Jan 2024 20:00:00 +0000;Mon, 15 Jan 2024 20:00:00 +0000;Mon, 8 Jan 2024 20:00:00 +0000;Mon, 1 Jan 2024 20:00:00 +0000;Mon, 25 Dec 2023 04:55:00 +0000;Mon, 18 Dec 2023 19:35:00 +0000;Mon, 11 Dec 2023 20:15:00 +0000;Mon, 4 Dec 2023 20:00:00 +0000;Mon, 27 Nov 2023 20:00:00 +0000;Mon, 20 Nov 2023 20:55:00 +0000;Mon, 13 Nov 2023 20:00:00 +0000;Mon, 6 Nov 2023 20:00:00 +0000;Mon, 30 Oct 2023 19:05:00 +0000;Mon, 23 Oct 2023 19:00:00 +0000;Mon, 16 Oct 2023 19:00:00 +0000;Mon, 9 Oct 2023 19:00:00 +0000;Mon, 2 Oct 2023 19:00:00 +0000;Mon, 25 Sep 2023 19:00:00 +0000;Mon, 18 Sep 2023 19:00:00 +0000;Mon, 11 Sep 2023 19:00:00 +0000;Mon, 4 Sep 2023 19:00:00 +0000;Mon, 28 Aug 2023 19:00:00 +0000;Mon, 21 Aug 2023 19:00:00 +0000;Mon, 14 Aug 2023 19:00:00 +0000;Mon, 7 Aug 2023 19:00:00 +0000;Mon, 31 Jul 2023 19:00:00 +0000;Mon, 24 Jul 2023 14:00:00 +0000;Mon, 17 Jul 2023 20:06:59 +0000;Mon, 10 Jul 2023 19:00:00 +0000;Mon, 3 Jul 2023 19:00:00 +0000;Mon, 26 Jun 2023 18:30:00 +0000;Mon, 19 Jun 2023 15:35:00 +0000;Mon, 12 Jun 2023 21:35:00 +0000;Thu, 8 Jun 2023 20:00:00 +0000;Mon, 5 Jun 2023 19:00:00 +0000;Mon, 29 May 2023 16:00:00 +0000;Mon, 22 May 2023 19:00:00 +0000;Mon, 15 May 2023 19:00:00 +0000;Sun, 14 May 2023 13:00:00 +0000;Mon, 8 May 2023 19:00:00 +0000;Mon, 1 May 2023 20:20:00 +0000;Mon, 24 Apr 2023 19:00:00 +0000;Mon, 17 Apr 2023 19:00:00 +0000;Mon, 10 Apr 2023 20:45:00 +0000;Thu, 6 Apr 2023 19:00:00 +0000;Mon, 3 Apr 2023 19:20:00 +0000;Mon, 27 Mar 2023 19:00:00 +0000
+Sat, 17 Feb 2024 08:03:00 -0000;Thu, 15 Feb 2024 08:03:00 -0000;Mon, 12 Feb 2024 08:03:00 -0000;Sat, 10 Feb 2024 08:03:00 -0000;Thu, 08 Feb 2024 08:03:00 -0000;Mon, 05 Feb 2024 08:03:00 -0000;Sat, 03 Feb 2024 08:03:00 -0000;Thu, 01 Feb 2024 08:03:00 -0000;Mon, 29 Jan 2024 08:03:00 -0000;Sat, 27 Jan 2024 08:03:00 -0000;Thu, 25 Jan 2024 08:03:00 -0000;Mon, 22 Jan 2024 08:03:00 -0000;Sat, 20 Jan 2024 08:03:00 -0000;Thu, 18 Jan 2024 08:03:00 -0000;Mon, 15 Jan 2024 08:03:00 -0000;Sat, 13 Jan 2024 08:03:00 -0000;Thu, 11 Jan 2024 08:03:00 -0000;Mon, 08 Jan 2024 08:03:00 -0000;Sat, 06 Jan 2024 08:03:00 -0000;Thu, 04 Jan 2024 08:03:00 -0000;Mon, 01 Jan 2024 08:03:00 -0000;Sat, 30 Dec 2023 08:03:00 -0000;Thu, 28 Dec 2023 08:03:00 -0000;Mon, 25 Dec 2023 08:03:00 -0000;Sat, 23 Dec 2023 08:03:00 -0000;Thu, 21 Dec 2023 08:03:00 -0000;Mon, 18 Dec 2023 08:03:00 -0000;Sat, 16 Dec 2023 08:03:00 -0000;Thu, 14 Dec 2023 08:03:00 -0000;Mon, 11 Dec 2023 08:03:00 -0000;Sat, 09 Dec 2023 08:03:00 -0000;Thu, 07 Dec 2023 08:03:00 -0000;Mon, 04 Dec 2023 08:03:00 -0000;Sat, 02 Dec 2023 08:02:00 -0000;Thu, 30 Nov 2023 08:03:00 -0000;Mon, 27 Nov 2023 08:02:00 -0000;Sat, 25 Nov 2023 08:03:00 -0000;Thu, 23 Nov 2023 08:03:00 -0000;Mon, 20 Nov 2023 08:03:00 -0000;Sat, 18 Nov 2023 08:03:00 -0000;Thu, 16 Nov 2023 08:03:00 -0000;Mon, 13 Nov 2023 08:03:00 -0000;Sat, 11 Nov 2023 08:03:00 -0000;Thu, 09 Nov 2023 08:03:00 -0000;Mon, 06 Nov 2023 08:03:00 -0000;Sat, 04 Nov 2023 07:03:00 -0000;Thu, 02 Nov 2023 07:03:00 -0000;Mon, 30 Oct 2023 07:03:00 -0000;Sat, 28 Oct 2023 07:03:00 -0000;Thu, 26 Oct 2023 07:03:00 -0000
+Thu, 15 Feb 2024 05:00:00 -0000;Thu, 08 Feb 2024 05:00:00 -0000;Thu, 01 Feb 2024 05:00:00 -0000;Thu, 18 Jan 2024 05:00:00 -0000;Mon, 04 Dec 2023 14:00:00 -0000;Fri, 01 Dec 2023 20:27:51 -0000;Thu, 16 Nov 2023 06:00:00 -0000;Mon, 06 Nov 2023 14:00:00 -0000;Tue, 10 Oct 2023 07:00:00 -0000;Tue, 03 Oct 2023 07:00:00 -0000;Tue, 26 Sep 2023 07:00:00 -0000;Tue, 19 Sep 2023 07:00:00 -0000;Tue, 12 Sep 2023 07:00:00 -0000;Tue, 05 Sep 2023 07:00:00 -0000;Tue, 22 Aug 2023 05:00:00 -0000;Tue, 08 Aug 2023 15:57:10 -0000;Mon, 20 Feb 2023 06:00:00 -0000;Mon, 13 Feb 2023 06:00:00 -0000;Mon, 06 Feb 2023 06:00:00 -0000;Mon, 30 Jan 2023 06:00:00 -0000;Mon, 23 Jan 2023 06:00:00 -0000;Mon, 16 Jan 2023 06:00:00 -0000;Mon, 09 Jan 2023 07:00:00 -0000;Mon, 09 Jan 2023 06:00:00 -0000;Thu, 15 Dec 2022 16:30:00 -0000;Mon, 12 Sep 2022 05:00:00 -0000;Mon, 05 Sep 2022 05:00:00 -0000;Mon, 29 Aug 2022 05:00:00 -0000;Mon, 22 Aug 2022 05:00:00 -0000;Mon, 15 Aug 2022 05:00:00 -0000;Mon, 08 Aug 2022 05:00:00 -0000;Mon, 01 Aug 2022 05:30:00 -0000;Mon, 01 Aug 2022 05:00:00 -0000;Wed, 20 Jul 2022 05:00:00 -0000;Tue, 15 Mar 2022 04:00:00 -0000;Tue, 08 Mar 2022 06:00:00 -0000;Tue, 01 Mar 2022 06:00:00 -0000;Tue, 22 Feb 2022 06:00:00 -0000;Tue, 15 Feb 2022 06:00:00 -0000;Tue, 08 Feb 2022 06:00:00 -0000;Tue, 01 Feb 2022 06:00:00 -0000;Tue, 25 Jan 2022 06:00:00 -0000;Tue, 25 Jan 2022 05:30:00 -0000;Tue, 11 Jan 2022 05:00:00 -0000;Tue, 10 Aug 2021 10:00:00 -0000;Tue, 03 Aug 2021 10:00:00 -0000;Tue, 27 Jul 2021 10:00:00 -0000;Tue, 20 Jul 2021 10:00:00 -0000;Tue, 13 Jul 2021 10:00:00 -0000;Tue, 06 Jul 2021 10:00:00 -0000
+Fri, 16 Feb 2024 20:47:41 +0000;Wed, 14 Feb 2024 20:32:20 +0000;Fri, 9 Feb 2024 21:03:32 +0000;Wed, 7 Feb 2024 14:30:00 +0000;Fri, 2 Feb 2024 21:58:03 +0000;Wed, 31 Jan 2024 20:33:59 +0000;Sat, 27 Jan 2024 00:03:42 +0000;Wed, 24 Jan 2024 18:00:00 +0000;Fri, 19 Jan 2024 20:12:32 +0000;Wed, 17 Jan 2024 21:39:01 +0000;Fri, 12 Jan 2024 22:22:11 +0000;Thu, 11 Jan 2024 02:42:28 +0000;Fri, 5 Jan 2024 21:00:00 +0000;Wed, 3 Jan 2024 22:01:36 +0000;Fri, 29 Dec 2023 14:30:00 +0000;Wed, 27 Dec 2023 14:30:00 +0000;Fri, 22 Dec 2023 18:45:01 +0000;Wed, 20 Dec 2023 21:28:17 +0000;Fri, 15 Dec 2023 23:35:37 +0000;Wed, 13 Dec 2023 19:58:04 +0000;Sat, 9 Dec 2023 02:44:12 +0000;Wed, 6 Dec 2023 22:34:27 +0000;Sat, 2 Dec 2023 02:14:42 +0000;Wed, 29 Nov 2023 21:32:00 +0000;Fri, 24 Nov 2023 14:00:00 +0000;Wed, 22 Nov 2023 14:00:00 +0000;Sat, 18 Nov 2023 01:05:42 +0000;Wed, 15 Nov 2023 19:52:23 +0000;Sat, 11 Nov 2023 02:48:07 +0000;Wed, 8 Nov 2023 21:52:31 +0000;Fri, 3 Nov 2023 18:45:38 +0000;Wed, 1 Nov 2023 21:07:55 +0000;Fri, 27 Oct 2023 21:32:43 +0000;Wed, 25 Oct 2023 23:19:25 +0000;Fri, 20 Oct 2023 16:00:00 +0000;Wed, 18 Oct 2023 23:24:01 +0000;Sat, 14 Oct 2023 03:35:19 +0000;Wed, 11 Oct 2023 19:23:49 +0000;Sat, 7 Oct 2023 00:00:19 +0000;Wed, 4 Oct 2023 16:43:05 +0000;Fri, 29 Sep 2023 13:00:00 +0000;Thu, 28 Sep 2023 00:13:31 +0000;Fri, 22 Sep 2023 20:47:03 +0000;Thu, 21 Sep 2023 00:03:51 +0000;Fri, 15 Sep 2023 20:42:33 +0000;Wed, 13 Sep 2023 22:10:40 +0000;Fri, 8 Sep 2023 23:41:04 +0000;Thu, 7 Sep 2023 16:00:00 +0000;Thu, 7 Sep 2023 00:52:11 +0000;Fri, 1 Sep 2023 16:00:00 +0000
+Fri, 16 Feb 2024 09:00:00 -0000;Fri, 09 Feb 2024 09:00:00 -0000;Wed, 07 Feb 2024 09:00:00 -0000;Fri, 02 Feb 2024 09:00:00 -0000;Fri, 26 Jan 2024 09:00:00 -0000;Fri, 19 Jan 2024 09:05:00 -0000;Fri, 19 Jan 2024 09:00:00 -0000;Fri, 12 Jan 2024 09:00:00 -0000;Fri, 05 Jan 2024 09:00:00 -0000;Fri, 22 Dec 2023 09:00:00 -0000;Fri, 15 Dec 2023 09:00:00 -0000;Fri, 08 Dec 2023 09:00:00 -0000;Fri, 01 Dec 2023 09:00:00 -0000;Fri, 24 Nov 2023 09:00:00 -0000;Fri, 17 Nov 2023 09:00:00 -0000;Fri, 10 Nov 2023 09:00:00 -0000;Fri, 03 Nov 2023 08:00:00 -0000;Fri, 27 Oct 2023 08:00:00 -0000;Fri, 20 Oct 2023 08:00:00 -0000;Fri, 13 Oct 2023 08:00:00 -0000;Wed, 11 Oct 2023 08:00:00 -0000;Fri, 06 Oct 2023 08:00:00 -0000;Fri, 29 Sep 2023 08:00:00 -0000;Thu, 28 Sep 2023 08:00:00 -0000;Fri, 22 Sep 2023 08:00:00 -0000;Fri, 15 Sep 2023 08:00:00 -0000;Fri, 08 Sep 2023 08:00:00 -0000;Fri, 25 Aug 2023 08:00:00 -0000;Mon, 21 Aug 2023 08:00:00 -0000;Fri, 18 Aug 2023 08:00:00 -0000;Fri, 11 Aug 2023 08:00:00 -0000;Fri, 04 Aug 2023 08:00:00 -0000;Fri, 28 Jul 2023 08:00:00 -0000;Fri, 21 Jul 2023 08:00:00 -0000;Fri, 14 Jul 2023 08:00:00 -0000;Fri, 07 Jul 2023 08:00:00 -0000;Fri, 30 Jun 2023 08:00:00 -0000;Fri, 23 Jun 2023 08:00:00 -0000;Fri, 16 Jun 2023 08:00:00 -0000;Fri, 09 Jun 2023 08:00:00 -0000;Fri, 02 Jun 2023 08:00:00 -0000;Fri, 26 May 2023 08:00:00 -0000;Fri, 19 May 2023 08:00:00 -0000;Fri, 12 May 2023 08:00:00 -0000;Fri, 05 May 2023 08:00:00 -0000;Fri, 28 Apr 2023 08:00:00 -0000;Fri, 21 Apr 2023 08:00:00 -0000;Fri, 14 Apr 2023 08:00:00 -0000;Fri, 07 Apr 2023 08:00:00 -0000;Fri, 24 Mar 2023 08:00:00 -0000
+Fri, 16 Feb 2024 11:00:00 -0000;Tue, 13 Feb 2024 11:00:00 -0000;Fri, 09 Feb 2024 11:00:00 -0000;Tue, 06 Feb 2024 11:00:00 -0000;Tue, 30 Jan 2024 11:00:00 -0000;Fri, 26 Jan 2024 11:00:00 -0000;Tue, 23 Jan 2024 23:07:00 -0000;Fri, 19 Jan 2024 11:00:00 -0000;Tue, 16 Jan 2024 11:00:00 -0000;Fri, 12 Jan 2024 16:59:00 -0000;Tue, 09 Jan 2024 11:00:00 -0000;Wed, 03 Jan 2024 11:00:00 -0000;Wed, 27 Dec 2023 11:00:00 -0000;Fri, 22 Dec 2023 11:00:00 -0000;Tue, 19 Dec 2023 11:00:00 -0000;Fri, 15 Dec 2023 11:00:00 -0000;Tue, 12 Dec 2023 11:00:00 -0000;Fri, 08 Dec 2023 11:00:00 -0000;Tue, 05 Dec 2023 11:00:00 -0000;Fri, 01 Dec 2023 15:30:00 -0000;Tue, 28 Nov 2023 11:00:00 -0000;Tue, 21 Nov 2023 11:00:00 -0000;Fri, 17 Nov 2023 11:00:00 -0000;Tue, 14 Nov 2023 11:00:00 -0000;Fri, 10 Nov 2023 11:00:00 -0000;Tue, 07 Nov 2023 11:00:00 -0000;Fri, 03 Nov 2023 10:00:00 -0000;Tue, 31 Oct 2023 19:22:00 -0000;Fri, 27 Oct 2023 10:00:00 -0000;Tue, 24 Oct 2023 10:00:00 -0000;Tue, 17 Oct 2023 10:00:00 -0000;Fri, 13 Oct 2023 10:00:00 -0000;Tue, 10 Oct 2023 10:00:00 -0000;Tue, 03 Oct 2023 10:00:00 -0000;Tue, 26 Sep 2023 10:00:00 -0000;Tue, 19 Sep 2023 10:00:00 -0000;Tue, 12 Sep 2023 10:00:00 -0000;Wed, 06 Sep 2023 10:00:00 -0000;Tue, 08 Aug 2023 10:00:00 -0000;Tue, 01 Aug 2023 10:00:00 -0000;Tue, 25 Jul 2023 10:00:00 -0000;Wed, 19 Jul 2023 19:46:27 -0000;Tue, 11 Jul 2023 10:00:00 -0000;Wed, 05 Jul 2023 18:12:10 -0000;Tue, 27 Jun 2023 10:00:00 -0000;Tue, 20 Jun 2023 10:00:00 -0000;Tue, 13 Jun 2023 10:00:00 -0000;Tue, 06 Jun 2023 10:00:00 -0000;Tue, 30 May 2023 10:00:00 -0000;Tue, 23 May 2023 10:00:00 -0000
+Wed, 14 Feb 2024 15:00:00 GMT;Wed, 07 Feb 2024 15:00:00 GMT;Wed, 31 Jan 2024 15:00:00 GMT;Wed, 24 Jan 2024 17:32:48 GMT;Wed, 17 Jan 2024 15:00:00 GMT;Wed, 10 Jan 2024 15:13:19 GMT;Thu, 04 Jan 2024 00:23:54 GMT;Wed, 27 Dec 2023 15:00:00 GMT;Wed, 20 Dec 2023 15:00:00 GMT;Wed, 13 Dec 2023 17:26:25 GMT;Thu, 07 Dec 2023 05:47:31 GMT;Wed, 29 Nov 2023 15:00:00 GMT;Wed, 22 Nov 2023 23:50:10 GMT;Wed, 15 Nov 2023 15:00:00 GMT;Wed, 08 Nov 2023 15:00:00 GMT;Wed, 01 Nov 2023 16:02:00 GMT;Wed, 01 Nov 2023 16:00:00 GMT;Wed, 25 Oct 2023 14:07:16 GMT
+Tue, 13 Feb 2024 08:30:00 +0000;Tue, 13 Feb 2024 08:30:00 +0000;Wed, 31 Jan 2024 17:07:45 +0000
+Tue, 13 Feb 2024 08:00:23 GMT;Tue, 06 Feb 2024 08:00:19 GMT;Tue, 30 Jan 2024 08:00:36 GMT;Tue, 23 Jan 2024 08:00:25 GMT;Tue, 16 Jan 2024 08:00:40 GMT;Tue, 09 Jan 2024 08:00:36 GMT;Tue, 02 Jan 2024 08:00:13 GMT;Fri, 27 Oct 2023 07:00:13 GMT;Tue, 04 Jul 2023 07:00:57 GMT;Tue, 27 Jun 2023 07:00:33 GMT;Tue, 20 Jun 2023 07:00:55 GMT;Tue, 13 Jun 2023 07:00:42 GMT;Tue, 06 Jun 2023 07:00:38 GMT;Tue, 30 May 2023 07:00:03 GMT;Tue, 23 May 2023 07:00:26 GMT;Tue, 09 May 2023 07:00:38 GMT;Tue, 02 May 2023 07:00:18 GMT;Tue, 25 Apr 2023 07:00:41 GMT;Tue, 18 Apr 2023 07:00:32 GMT;Tue, 11 Apr 2023 07:00:30 GMT;Tue, 04 Apr 2023 07:00:54 GMT;Tue, 21 Mar 2023 07:00:16 GMT;Tue, 16 Aug 2022 07:00:37 GMT;Tue, 09 Aug 2022 07:00:43 GMT;Tue, 02 Aug 2022 07:00:13 GMT;Tue, 26 Jul 2022 07:00:18 GMT;Tue, 19 Jul 2022 07:00:01 GMT;Tue, 12 Jul 2022 07:00:47 GMT;Tue, 05 Jul 2022 07:00:38 GMT;Tue, 24 May 2022 07:00:59 GMT;Tue, 17 May 2022 07:00:12 GMT;Tue, 10 May 2022 07:00:50 GMT;Tue, 03 May 2022 07:00:28 GMT;Tue, 26 Apr 2022 07:00:28 GMT;Tue, 19 Apr 2022 07:00:13 GMT;Tue, 12 Apr 2022 07:00:33 GMT;Tue, 26 Oct 2021 07:00:00 GMT;Tue, 19 Oct 2021 07:00:00 GMT;Tue, 12 Oct 2021 07:00:00 GMT;Tue, 05 Oct 2021 07:00:00 GMT;Tue, 28 Sep 2021 07:00:00 GMT;Tue, 21 Sep 2021 07:00:00 GMT;Wed, 01 Sep 2021 18:50:16 GMT
+Fri, 16 Feb 2024 06:00:00 -0000;Thu, 15 Feb 2024 06:00:00 -0000;Mon, 12 Feb 2024 06:00:00 -0000;Fri, 09 Feb 2024 06:00:00 -0000;Thu, 08 Feb 2024 06:00:00 -0000;Mon, 05 Feb 2024 06:00:00 -0000;Fri, 02 Feb 2024 06:00:00 -0000;Thu, 01 Feb 2024 06:00:00 -0000;Mon, 29 Jan 2024 06:00:00 -0000;Fri, 26 Jan 2024 06:00:00 -0000;Thu, 25 Jan 2024 06:00:00 -0000;Mon, 22 Jan 2024 06:00:00 -0000;Fri, 19 Jan 2024 06:00:00 -0000;Thu, 18 Jan 2024 06:00:00 -0000;Mon, 15 Jan 2024 06:00:00 -0000;Fri, 12 Jan 2024 06:00:00 -0000;Thu, 11 Jan 2024 06:00:00 -0000;Mon, 08 Jan 2024 06:00:00 -0000;Fri, 05 Jan 2024 06:00:00 -0000;Thu, 04 Jan 2024 06:00:00 -0000;Mon, 01 Jan 2024 06:00:00 -0000;Fri, 29 Dec 2023 06:00:00 -0000;Thu, 28 Dec 2023 06:00:00 -0000;Tue, 26 Dec 2023 05:54:00 -0000;Fri, 22 Dec 2023 06:00:00 -0000;Thu, 21 Dec 2023 10:32:00 -0000;Mon, 18 Dec 2023 06:00:00 -0000;Fri, 15 Dec 2023 06:00:00 -0000;Thu, 14 Dec 2023 06:00:00 -0000;Mon, 11 Dec 2023 06:00:00 -0000;Fri, 08 Dec 2023 06:00:00 -0000;Thu, 07 Dec 2023 06:00:00 -0000;Mon, 04 Dec 2023 06:00:00 -0000;Fri, 01 Dec 2023 06:00:00 -0000;Thu, 30 Nov 2023 11:48:00 -0000;Mon, 27 Nov 2023 06:00:00 -0000;Fri, 24 Nov 2023 06:00:00 -0000;Thu, 23 Nov 2023 06:00:00 -0000;Mon, 20 Nov 2023 06:00:00 -0000;Fri, 17 Nov 2023 06:00:00 -0000;Thu, 16 Nov 2023 06:00:00 -0000;Mon, 13 Nov 2023 06:00:00 -0000;Fri, 10 Nov 2023 06:00:00 -0000;Thu, 09 Nov 2023 06:00:00 -0000;Mon, 06 Nov 2023 06:00:00 -0000;Fri, 03 Nov 2023 06:00:00 -0000;Thu, 02 Nov 2023 06:00:00 -0000;Mon, 30 Oct 2023 06:00:00 -0000;Fri, 27 Oct 2023 05:00:00 -0000;Thu, 26 Oct 2023 05:00:00 -0000
+Mon, 12 Feb 2024 13:00:00 -0000;Mon, 05 Feb 2024 13:00:00 -0000;Mon, 29 Jan 2024 13:00:00 -0000;Mon, 22 Jan 2024 13:00:00 -0000;Mon, 15 Jan 2024 13:00:00 -0000;Mon, 08 Jan 2024 13:00:00 -0000;Mon, 01 Jan 2024 16:00:00 -0000;Mon, 18 Dec 2023 13:00:00 -0000;Mon, 11 Dec 2023 13:00:00 -0000;Mon, 04 Dec 2023 13:00:00 -0000;Mon, 27 Nov 2023 13:00:00 -0000;Mon, 20 Nov 2023 13:00:00 -0000;Mon, 13 Nov 2023 13:00:00 -0000;Mon, 06 Nov 2023 13:00:00 -0000;Mon, 30 Oct 2023 12:00:00 -0000;Mon, 23 Oct 2023 12:00:00 -0000;Mon, 16 Oct 2023 12:00:00 -0000;Mon, 09 Oct 2023 12:00:00 -0000;Mon, 02 Oct 2023 12:00:00 -0000;Mon, 25 Sep 2023 12:00:00 -0000;Mon, 18 Sep 2023 12:00:00 -0000;Mon, 11 Sep 2023 12:00:00 -0000;Mon, 04 Sep 2023 12:00:00 -0000;Mon, 28 Aug 2023 12:00:00 -0000;Mon, 21 Aug 2023 12:00:00 -0000;Mon, 14 Aug 2023 12:00:00 -0000;Mon, 07 Aug 2023 12:00:00 -0000;Mon, 31 Jul 2023 12:00:00 -0000;Mon, 24 Jul 2023 12:00:00 -0000;Mon, 17 Jul 2023 12:00:00 -0000;Mon, 10 Jul 2023 12:00:00 -0000;Mon, 03 Jul 2023 12:00:00 -0000;Mon, 26 Jun 2023 12:00:00 -0000;Mon, 19 Jun 2023 12:00:00 -0000;Mon, 12 Jun 2023 12:00:00 -0000;Mon, 05 Jun 2023 12:00:00 -0000;Mon, 29 May 2023 12:00:00 -0000;Mon, 22 May 2023 12:00:00 -0000;Mon, 15 May 2023 12:00:00 -0000;Mon, 08 May 2023 12:00:00 -0000;Mon, 01 May 2023 12:00:00 -0000;Mon, 24 Apr 2023 12:00:00 -0000;Mon, 17 Apr 2023 12:00:00 -0000;Mon, 10 Apr 2023 12:00:00 -0000;Mon, 03 Apr 2023 12:00:00 -0000;Mon, 27 Mar 2023 12:00:00 -0000;Thu, 23 Mar 2023 12:00:00 -0000;Mon, 20 Mar 2023 12:00:00 -0000;Mon, 13 Mar 2023 12:00:00 -0000;Mon, 06 Mar 2023 13:00:00 -0000
+Thu, 15 Feb 2024 05:01:00 -0000;Tue, 13 Feb 2024 05:01:00 -0000;Thu, 08 Feb 2024 05:01:00 -0000;Tue, 06 Feb 2024 05:01:00 -0000;Thu, 01 Feb 2024 05:01:00 -0000;Tue, 30 Jan 2024 05:01:00 -0000;Thu, 25 Jan 2024 05:01:00 -0000;Tue, 23 Jan 2024 05:01:00 -0000;Thu, 18 Jan 2024 05:01:00 -0000;Tue, 16 Jan 2024 05:01:00 -0000;Thu, 11 Jan 2024 05:01:00 -0000;Tue, 09 Jan 2024 05:01:00 -0000;Thu, 04 Jan 2024 05:01:00 -0000;Tue, 02 Jan 2024 05:01:00 -0000;Thu, 21 Dec 2023 05:01:00 -0000;Tue, 19 Dec 2023 05:01:00 -0000;Thu, 14 Dec 2023 05:01:00 -0000;Tue, 12 Dec 2023 05:01:00 -0000;Thu, 07 Dec 2023 05:01:00 -0000;Tue, 05 Dec 2023 05:01:00 -0000;Thu, 30 Nov 2023 05:01:00 -0000;Tue, 28 Nov 2023 05:01:00 -0000;Thu, 23 Nov 2023 05:01:00 -0000;Tue, 21 Nov 2023 05:01:00 -0000;Thu, 16 Nov 2023 05:01:00 -0000;Tue, 14 Nov 2023 05:01:00 -0000;Thu, 09 Nov 2023 05:01:00 -0000;Tue, 07 Nov 2023 05:01:00 -0000;Thu, 02 Nov 2023 04:01:00 -0000;Tue, 31 Oct 2023 04:01:00 -0000;Thu, 26 Oct 2023 04:01:00 -0000;Tue, 24 Oct 2023 04:01:00 -0000;Thu, 19 Oct 2023 04:01:00 -0000;Tue, 17 Oct 2023 04:01:00 -0000;Thu, 12 Oct 2023 04:01:00 -0000;Tue, 10 Oct 2023 04:01:00 -0000;Thu, 05 Oct 2023 04:01:00 -0000;Tue, 03 Oct 2023 04:01:00 -0000;Thu, 28 Sep 2023 04:01:00 -0000;Tue, 26 Sep 2023 04:01:00 -0000;Fri, 22 Sep 2023 06:13:01 -0000;Thu, 21 Sep 2023 04:01:00 -0000;Tue, 19 Sep 2023 04:01:00 -0000;Thu, 14 Sep 2023 04:01:00 -0000;Wed, 13 Sep 2023 04:01:00 -0000;Tue, 12 Sep 2023 04:01:00 -0000;Thu, 07 Sep 2023 04:01:00 -0000;Tue, 05 Sep 2023 04:01:00 -0000;Thu, 17 Aug 2023 04:01:00 -0000;Tue, 15 Aug 2023 04:01:00 -0000
+Tue, 13 Feb 2024 08:04:00 -0000;Tue, 06 Feb 2024 08:03:00 -0000;Tue, 30 Jan 2024 08:02:00 -0000;Tue, 23 Jan 2024 08:01:00 -0000;Mon, 22 Jan 2024 09:00:00 -0000;Tue, 16 Jan 2024 08:00:00 -0000;Tue, 09 Jan 2024 08:03:00 -0000;Tue, 02 Jan 2024 08:02:00 -0000;Tue, 26 Dec 2023 08:01:00 -0000;Tue, 19 Dec 2023 08:01:00 -0000;Tue, 12 Dec 2023 08:04:00 -0000;Tue, 05 Dec 2023 08:03:00 -0000;Tue, 28 Nov 2023 08:02:00 -0000;Tue, 21 Nov 2023 08:01:00 -0000;Tue, 14 Nov 2023 08:01:00 -0000;Tue, 07 Nov 2023 08:01:00 -0000;Tue, 31 Oct 2023 07:01:00 -0000;Tue, 24 Oct 2023 07:01:00 -0000;Tue, 17 Oct 2023 07:01:00 -0000;Tue, 10 Oct 2023 07:05:00 -0000;Tue, 03 Oct 2023 07:04:00 -0000;Tue, 26 Sep 2023 07:03:00 -0000;Tue, 19 Sep 2023 07:02:00 -0000;Tue, 12 Sep 2023 07:01:00 -0000;Tue, 05 Sep 2023 07:01:00 -0000;Tue, 29 Aug 2023 07:02:00 -0000;Tue, 22 Aug 2023 07:01:00 -0000;Tue, 15 Aug 2023 07:01:00 -0000;Tue, 08 Aug 2023 07:01:00 -0000;Tue, 01 Aug 2023 07:01:00 -0000;Tue, 25 Jul 2023 07:01:00 -0000;Tue, 18 Jul 2023 07:01:00 -0000;Tue, 11 Jul 2023 07:01:00 -0000;Tue, 04 Jul 2023 07:04:00 -0000;Tue, 27 Jun 2023 07:03:00 -0000;Tue, 20 Jun 2023 07:01:00 -0000;Tue, 13 Jun 2023 07:01:00 -0000;Tue, 06 Jun 2023 07:01:00 -0000;Tue, 30 May 2023 07:01:00 -0000;Tue, 23 May 2023 07:01:00 -0000;Tue, 16 May 2023 07:01:00 -0000;Tue, 09 May 2023 07:01:00 -0000;Tue, 02 May 2023 07:01:00 -0000;Tue, 25 Apr 2023 07:01:00 -0000;Tue, 18 Apr 2023 07:01:00 -0000;Tue, 11 Apr 2023 07:01:00 -0000;Tue, 04 Apr 2023 07:01:00 -0000;Tue, 28 Mar 2023 07:01:00 -0000;Tue, 21 Mar 2023 07:01:00 -0000;Tue, 14 Mar 2023 07:01:00 -0000
+Mon, 12 Feb 2024 11:00:00 -0000;Mon, 05 Feb 2024 11:00:00 -0000;Mon, 29 Jan 2024 11:00:00 -0000;Mon, 22 Jan 2024 11:00:00 -0000;Mon, 15 Jan 2024 11:00:00 -0000;Mon, 08 Jan 2024 11:00:00 -0000;Mon, 25 Dec 2023 05:00:00 -0000;Wed, 20 Dec 2023 11:00:00 -0000;Mon, 18 Dec 2023 11:00:00 -0000;Wed, 13 Dec 2023 11:00:00 -0000;Tue, 12 Dec 2023 11:00:00 -0000;Mon, 11 Dec 2023 11:00:00 -0000;Wed, 06 Dec 2023 11:00:00 -0000;Mon, 04 Dec 2023 11:00:00 -0000;Wed, 29 Nov 2023 11:00:00 -0000;Mon, 27 Nov 2023 11:00:00 -0000;Thu, 23 Nov 2023 11:00:00 -0000;Tue, 21 Nov 2023 11:00:00 -0000;Mon, 20 Nov 2023 11:00:00 -0000;Wed, 15 Nov 2023 11:00:00 -0000;Tue, 14 Nov 2023 11:00:00 -0000;Mon, 13 Nov 2023 11:00:00 -0000;Wed, 08 Nov 2023 11:00:00 -0000;Mon, 06 Nov 2023 11:00:00 -0000;Wed, 01 Nov 2023 10:00:00 -0000;Mon, 30 Oct 2023 10:00:00 -0000;Thu, 26 Oct 2023 10:00:00 -0000;Wed, 25 Oct 2023 10:00:00 -0000;Tue, 24 Oct 2023 10:00:00 -0000;Mon, 23 Oct 2023 10:00:00 -0000;Wed, 18 Oct 2023 10:00:00 -0000;Mon, 16 Oct 2023 10:00:00 -0000;Wed, 11 Oct 2023 10:00:00 -0000;Mon, 09 Oct 2023 10:00:00 -0000;Wed, 04 Oct 2023 10:00:00 -0000;Tue, 03 Oct 2023 10:00:00 -0000;Mon, 02 Oct 2023 10:00:00 -0000;Wed, 27 Sep 2023 10:00:00 -0000;Mon, 25 Sep 2023 10:00:00 -0000;Mon, 18 Sep 2023 10:00:00 -0000;Mon, 11 Sep 2023 10:00:00 -0000;Mon, 04 Sep 2023 10:00:00 -0000;Wed, 30 Aug 2023 10:00:00 -0000;Mon, 28 Aug 2023 10:00:00 -0000;Mon, 21 Aug 2023 10:00:00 -0000;Mon, 14 Aug 2023 10:00:00 -0000;Mon, 07 Aug 2023 10:00:00 -0000;Mon, 31 Jul 2023 10:00:00 -0000;Mon, 24 Jul 2023 10:00:00 -0000;Fri, 21 Jul 2023 10:00:00 -0000
+Sat, 17 Feb 2024 06:00:00 -0000;Thu, 15 Feb 2024 06:00:00 -0000;Mon, 12 Feb 2024 06:00:00 -0000;Sat, 10 Feb 2024 06:00:00 -0000;Thu, 08 Feb 2024 06:00:00 -0000;Mon, 05 Feb 2024 06:00:00 -0000;Sat, 03 Feb 2024 06:00:00 -0000;Thu, 01 Feb 2024 06:00:00 -0000;Mon, 29 Jan 2024 06:00:00 -0000;Sat, 27 Jan 2024 06:00:00 -0000;Thu, 25 Jan 2024 06:00:00 -0000;Mon, 22 Jan 2024 06:00:00 -0000;Sat, 20 Jan 2024 06:00:00 -0000;Thu, 18 Jan 2024 06:00:00 -0000;Mon, 15 Jan 2024 06:00:00 -0000;Sat, 13 Jan 2024 06:00:00 -0000;Thu, 11 Jan 2024 06:00:00 -0000;Mon, 08 Jan 2024 06:00:00 -0000;Sat, 06 Jan 2024 06:00:00 -0000;Thu, 04 Jan 2024 06:00:00 -0000;Mon, 01 Jan 2024 06:00:00 -0000;Sat, 30 Dec 2023 06:00:00 -0000;Thu, 28 Dec 2023 06:00:00 -0000;Sat, 23 Dec 2023 06:00:00 -0000;Thu, 21 Dec 2023 06:00:00 -0000;Mon, 18 Dec 2023 06:00:00 -0000;Sat, 16 Dec 2023 06:00:00 -0000;Thu, 14 Dec 2023 06:00:00 -0000;Mon, 11 Dec 2023 06:00:00 -0000;Sat, 09 Dec 2023 06:00:00 -0000;Thu, 07 Dec 2023 06:00:00 -0000;Mon, 04 Dec 2023 06:00:00 -0000;Sat, 02 Dec 2023 06:00:00 -0000;Thu, 30 Nov 2023 06:00:00 -0000;Mon, 27 Nov 2023 06:00:00 -0000;Sat, 25 Nov 2023 06:00:00 -0000;Thu, 23 Nov 2023 06:00:00 -0000;Mon, 20 Nov 2023 06:00:00 -0000;Sat, 18 Nov 2023 06:00:00 -0000;Thu, 16 Nov 2023 06:00:00 -0000;Mon, 13 Nov 2023 06:00:00 -0000;Sat, 11 Nov 2023 06:00:00 -0000;Thu, 09 Nov 2023 06:00:00 -0000;Mon, 06 Nov 2023 06:00:00 -0000;Sat, 04 Nov 2023 05:00:00 -0000;Thu, 02 Nov 2023 05:00:00 -0000;Mon, 30 Oct 2023 05:00:00 -0000;Sat, 28 Oct 2023 05:00:00 -0000;Thu, 26 Oct 2023 05:00:00 -0000;Mon, 23 Oct 2023 05:00:00 -0000
+Thu, 15 Feb 2024 01:00:00 +0000;Thu, 08 Feb 2024 01:00:00 +0000;Thu, 01 Feb 2024 01:00:00 +0000;Thu, 25 Jan 2024 01:00:00 +0000;Mon, 08 Jan 2024 15:00:00 +0000;Thu, 21 Dec 2023 01:00:00 +0000;Thu, 14 Dec 2023 01:00:00 +0000;Thu, 07 Dec 2023 01:00:00 +0000;Thu, 30 Nov 2023 01:00:00 +0000;Thu, 23 Nov 2023 01:00:00 +0000;Thu, 16 Nov 2023 01:00:00 +0000;Thu, 09 Nov 2023 01:00:00 +0000;Thu, 02 Nov 2023 00:00:00 +0000;Thu, 26 Oct 2023 00:00:00 +0000;Thu, 25 May 2023 00:00:00 +0000;Thu, 18 May 2023 00:00:00 +0000;Thu, 11 May 2023 00:00:00 +0000;Thu, 04 May 2023 00:00:00 +0000;Thu, 27 Apr 2023 00:00:00 +0000;Thu, 20 Apr 2023 00:00:00 +0000;Thu, 13 Apr 2023 00:00:00 +0000;Thu, 06 Apr 2023 00:00:00 +0000;Thu, 30 Mar 2023 00:00:00 +0000;Thu, 16 Feb 2023 01:00:00 +0000;Thu, 09 Feb 2023 01:00:00 +0000;Thu, 02 Feb 2023 01:00:00 +0000;Thu, 26 Jan 2023 01:00:00 +0000;Thu, 19 Jan 2023 01:00:00 +0000;Thu, 12 Jan 2023 01:00:00 +0000;Thu, 15 Dec 2022 01:00:00 +0000;Thu, 13 Oct 2022 00:00:00 +0000;Thu, 06 Oct 2022 00:00:00 +0000;Thu, 29 Sep 2022 00:00:00 +0000;Thu, 22 Sep 2022 00:00:00 +0000;Thu, 15 Sep 2022 00:00:00 +0000;Thu, 08 Sep 2022 00:00:00 +0000;Thu, 28 Jul 2022 00:00:00 +0000;Thu, 21 Jul 2022 00:00:00 +0000;Thu, 14 Jul 2022 00:00:00 +0000;Thu, 07 Jul 2022 00:00:00 +0000;Thu, 30 Jun 2022 00:00:00 +0000;Thu, 23 Jun 2022 00:00:00 +0000;Thu, 16 Jun 2022 00:00:00 +0000;Thu, 09 Jun 2022 00:00:00 +0000;Thu, 02 Jun 2022 00:00:00 +0000;Thu, 21 Apr 2022 00:00:00 +0000;Thu, 14 Apr 2022 00:00:00 +0000;Thu, 07 Apr 2022 00:00:00 +0000;Thu, 31 Mar 2022 00:00:00 +0000;Thu, 24 Mar 2022 00:00:00 +0000
+Sun, 18 Feb 2024 08:00:00 -0000;Fri, 16 Feb 2024 09:00:00 -0000;Wed, 14 Feb 2024 08:00:00 -0000;Mon, 12 Feb 2024 08:00:00 -0000;Fri, 09 Feb 2024 08:00:00 -0000;Wed, 07 Feb 2024 08:00:00 -0000;Mon, 05 Feb 2024 08:00:00 -0000;Sun, 04 Feb 2024 05:00:00 -0000;Fri, 02 Feb 2024 08:00:00 -0000;Wed, 31 Jan 2024 08:00:00 -0000;Mon, 29 Jan 2024 08:00:00 -0000;Fri, 26 Jan 2024 08:00:00 -0000;Wed, 24 Jan 2024 08:00:00 -0000;Mon, 22 Jan 2024 08:00:00 -0000;Sun, 21 Jan 2024 08:00:00 -0000;Fri, 19 Jan 2024 08:00:00 -0000;Wed, 17 Jan 2024 09:00:00 -0000;Mon, 15 Jan 2024 09:00:00 -0000;Sun, 14 Jan 2024 08:00:00 -0000;Fri, 12 Jan 2024 09:00:00 -0000;Wed, 10 Jan 2024 09:00:00 -0000;Mon, 08 Jan 2024 09:00:00 -0000;Sun, 07 Jan 2024 08:00:00 -0000;Fri, 05 Jan 2024 08:00:00 -0000;Wed, 03 Jan 2024 08:00:00 -0000;Mon, 01 Jan 2024 08:00:00 -0000;Sun, 31 Dec 2023 08:00:00 -0000;Fri, 29 Dec 2023 09:00:00 -0000;Wed, 27 Dec 2023 09:00:00 -0000;Mon, 25 Dec 2023 09:00:00 -0000;Sun, 24 Dec 2023 08:00:00 -0000;Fri, 22 Dec 2023 09:00:00 -0000;Wed, 20 Dec 2023 09:00:00 -0000;Mon, 18 Dec 2023 09:00:00 -0000;Sun, 17 Dec 2023 08:00:00 -0000;Fri, 15 Dec 2023 08:00:00 -0000;Wed, 13 Dec 2023 08:00:00 -0000;Mon, 11 Dec 2023 08:00:00 -0000;Sun, 10 Dec 2023 08:00:00 -0000;Fri, 08 Dec 2023 08:00:00 -0000;Wed, 06 Dec 2023 09:00:00 -0000;Mon, 04 Dec 2023 08:00:00 -0000;Fri, 01 Dec 2023 08:00:00 -0000;Wed, 29 Nov 2023 08:00:00 -0000;Mon, 27 Nov 2023 08:00:00 -0000;Sun, 26 Nov 2023 08:00:00 -0000;Wed, 22 Nov 2023 08:00:00 -0000;Mon, 20 Nov 2023 08:00:00 -0000;Sun, 19 Nov 2023 08:00:00 -0000;Fri, 17 Nov 2023 08:00:00 -0000
+Wed, 14 Feb 2024 08:00:00 -0000;Tue, 13 Feb 2024 08:00:00 -0000;Wed, 07 Feb 2024 08:00:00 -0000;Tue, 06 Feb 2024 08:00:00 -0000;Wed, 31 Jan 2024 08:00:00 -0000;Tue, 30 Jan 2024 08:00:00 -0000;Wed, 24 Jan 2024 08:00:00 -0000;Tue, 23 Jan 2024 08:00:00 -0000;Wed, 17 Jan 2024 08:00:00 -0000;Tue, 16 Jan 2024 08:00:00 -0000;Wed, 10 Jan 2024 08:00:00 -0000;Tue, 09 Jan 2024 08:00:00 -0000;Wed, 03 Jan 2024 08:00:00 -0000;Tue, 02 Jan 2024 08:00:00 -0000;Wed, 27 Dec 2023 08:00:00 -0000;Tue, 26 Dec 2023 08:00:00 -0000;Wed, 20 Dec 2023 08:00:00 -0000;Tue, 19 Dec 2023 08:00:00 -0000;Wed, 13 Dec 2023 08:00:00 -0000;Tue, 12 Dec 2023 08:00:00 -0000;Wed, 06 Dec 2023 08:00:00 -0000;Tue, 05 Dec 2023 08:00:00 -0000;Wed, 29 Nov 2023 08:00:00 -0000;Tue, 28 Nov 2023 08:00:00 -0000;Mon, 27 Nov 2023 08:00:00 -0000;Wed, 22 Nov 2023 08:00:00 -0000;Tue, 21 Nov 2023 08:00:00 -0000;Wed, 15 Nov 2023 08:00:00 -0000;Tue, 14 Nov 2023 08:00:00 -0000;Wed, 08 Nov 2023 08:00:00 -0000;Tue, 07 Nov 2023 08:00:00 -0000;Wed, 01 Nov 2023 07:00:00 -0000;Tue, 31 Oct 2023 07:00:00 -0000;Wed, 25 Oct 2023 07:00:00 -0000;Tue, 24 Oct 2023 07:00:00 -0000;Wed, 18 Oct 2023 07:00:00 -0000;Tue, 17 Oct 2023 07:00:00 -0000;Wed, 11 Oct 2023 07:00:00 -0000;Tue, 10 Oct 2023 07:00:00 -0000;Wed, 04 Oct 2023 07:00:00 -0000;Tue, 03 Oct 2023 07:00:00 -0000;Wed, 27 Sep 2023 07:00:00 -0000;Tue, 26 Sep 2023 07:00:00 -0000;Wed, 20 Sep 2023 07:00:00 -0000;Tue, 19 Sep 2023 07:00:00 -0000;Wed, 13 Sep 2023 07:00:00 -0000;Tue, 12 Sep 2023 07:00:00 -0000;Wed, 06 Sep 2023 07:00:00 -0000;Tue, 05 Sep 2023 07:00:00 -0000;Wed, 30 Aug 2023 07:00:00 -0000
+Fri, 16 Feb 2024 05:00:00 -0000;Tue, 13 Feb 2024 05:00:00 -0000;Tue, 06 Feb 2024 05:00:00 -0000;Fri, 02 Feb 2024 05:00:00 -0000;Tue, 30 Jan 2024 05:00:00 -0000;Tue, 23 Jan 2024 05:00:00 -0000;Fri, 19 Jan 2024 05:00:00 -0000;Tue, 16 Jan 2024 05:00:00 -0000;Tue, 09 Jan 2024 05:00:00 -0000;Sat, 06 Jan 2024 05:00:00 -0000;Fri, 05 Jan 2024 05:00:00 -0000;Tue, 02 Jan 2024 05:00:00 -0000;Tue, 26 Dec 2023 05:00:00 -0000;Tue, 19 Dec 2023 05:00:00 -0000;Fri, 15 Dec 2023 05:00:00 -0000;Tue, 12 Dec 2023 05:00:00 -0000;Tue, 05 Dec 2023 05:00:00 -0000;Fri, 01 Dec 2023 05:00:00 -0000;Tue, 28 Nov 2023 05:00:00 -0000;Fri, 24 Nov 2023 05:00:00 -0000;Tue, 21 Nov 2023 05:00:00 -0000;Fri, 17 Nov 2023 05:00:00 -0000;Tue, 14 Nov 2023 05:00:00 -0000;Fri, 10 Nov 2023 05:00:00 -0000;Tue, 07 Nov 2023 05:00:00 -0000;Tue, 31 Oct 2023 04:00:00 -0000;Fri, 27 Oct 2023 04:00:00 -0000;Tue, 24 Oct 2023 04:00:00 -0000;Fri, 20 Oct 2023 04:00:00 -0000;Tue, 17 Oct 2023 04:00:00 -0000;Tue, 10 Oct 2023 04:00:00 -0000;Fri, 06 Oct 2023 04:00:00 -0000;Tue, 03 Oct 2023 04:00:00 -0000;Fri, 29 Sep 2023 04:00:00 -0000;Tue, 26 Sep 2023 04:00:00 -0000;Fri, 22 Sep 2023 04:00:00 -0000;Tue, 19 Sep 2023 04:00:00 -0000;Fri, 15 Sep 2023 04:00:00 -0000;Tue, 12 Sep 2023 04:00:00 -0000;Tue, 05 Sep 2023 04:00:00 -0000;Fri, 01 Sep 2023 04:00:00 -0000;Tue, 29 Aug 2023 04:00:00 -0000;Tue, 22 Aug 2023 04:00:00 -0000;Fri, 18 Aug 2023 04:00:00 -0000;Tue, 15 Aug 2023 04:00:00 -0000;Fri, 11 Aug 2023 04:00:00 -0000;Tue, 08 Aug 2023 04:00:00 -0000;Tue, 01 Aug 2023 04:00:00 -0000;Fri, 28 Jul 2023 04:00:00 -0000;Tue, 25 Jul 2023 04:00:00 -0000
+Fri, 16 Feb 2024 21:20:02 +0000;Thu, 15 Feb 2024 21:00:00 +0000;Wed, 14 Feb 2024 21:00:00 +0000;Wed, 14 Feb 2024 04:21:07 +0000;Tue, 13 Feb 2024 21:46:20 +0000;Mon, 12 Feb 2024 21:01:58 +0000;Fri, 9 Feb 2024 21:53:59 +0000;Thu, 8 Feb 2024 21:00:00 +0000;Wed, 7 Feb 2024 21:00:00 +0000;Tue, 6 Feb 2024 21:05:35 +0000;Mon, 5 Feb 2024 21:00:00 +0000;Fri, 2 Feb 2024 21:00:00 +0000;Thu, 1 Feb 2024 21:00:00 +0000;Wed, 31 Jan 2024 21:00:00 +0000;Tue, 30 Jan 2024 21:00:00 +0000;Mon, 29 Jan 2024 21:00:00 +0000;Fri, 26 Jan 2024 21:00:00 +0000;Thu, 25 Jan 2024 21:00:00 +0000;Wed, 24 Jan 2024 21:00:00 +0000;Tue, 23 Jan 2024 21:00:00 +0000;Mon, 22 Jan 2024 21:00:00 +0000;Fri, 19 Jan 2024 21:00:00 +0000;Thu, 18 Jan 2024 21:56:26 +0000;Wed, 17 Jan 2024 21:00:00 +0000;Tue, 16 Jan 2024 21:00:00 +0000;Mon, 15 Jan 2024 21:00:00 +0000;Fri, 12 Jan 2024 21:00:00 +0000;Thu, 11 Jan 2024 21:00:00 +0000;Wed, 10 Jan 2024 21:00:00 +0000;Tue, 9 Jan 2024 21:00:00 +0000;Mon, 8 Jan 2024 21:00:00 +0000;Fri, 5 Jan 2024 20:59:40 +0000;Thu, 4 Jan 2024 21:00:00 +0000;Wed, 3 Jan 2024 21:00:00 +0000;Mon, 27 Nov 2023 13:00:00 +0000;Fri, 24 Nov 2023 13:00:00 +0000;Mon, 20 Nov 2023 20:18:01 +0000;Sat, 18 Nov 2023 13:00:00 +0000;Fri, 17 Nov 2023 21:01:52 +0000;Mon, 13 Nov 2023 22:00:00 +0000;Fri, 10 Nov 2023 22:00:00 +0000;Thu, 9 Nov 2023 22:00:00 +0000;Wed, 8 Nov 2023 22:00:00 +0000;Tue, 7 Nov 2023 22:02:11 +0000;Mon, 6 Nov 2023 22:00:00 +0000;Fri, 3 Nov 2023 22:06:13 +0000;Thu, 2 Nov 2023 19:41:39 +0000;Tue, 31 Oct 2023 21:00:00 +0000;Mon, 30 Oct 2023 18:28:10 +0000;Fri, 27 Oct 2023 21:47:54 +0000
+Mon, 12 Feb 2024 09:00:00 +0000;Mon, 05 Feb 2024 09:00:00 +0000;Mon, 29 Jan 2024 09:00:00 +0000;Mon, 22 Jan 2024 09:00:00 +0000;Mon, 15 Jan 2024 09:00:00 +0000;Mon, 08 Jan 2024 09:00:00 +0000;Mon, 01 Jan 2024 09:00:00 +0000;Mon, 18 Dec 2023 09:00:00 +0000;Mon, 11 Dec 2023 09:00:00 +0000;Mon, 04 Dec 2023 09:00:00 +0000;Mon, 27 Nov 2023 09:00:00 +0000;Mon, 20 Nov 2023 09:00:00 +0000;Mon, 13 Nov 2023 09:00:00 +0000;Mon, 06 Nov 2023 09:00:00 +0000;Mon, 30 Oct 2023 08:00:00 +0000;Mon, 23 Oct 2023 08:00:00 +0000;Mon, 16 Oct 2023 08:00:00 +0000;Mon, 09 Oct 2023 08:00:00 +0000;Mon, 02 Oct 2023 08:00:00 +0000;Mon, 25 Sep 2023 08:00:00 +0000;Mon, 18 Sep 2023 08:00:00 +0000;Mon, 11 Sep 2023 08:00:00 +0000;Mon, 04 Sep 2023 08:00:00 +0000;Mon, 28 Aug 2023 08:00:00 +0000;Mon, 21 Aug 2023 08:00:00 +0000;Mon, 14 Aug 2023 08:00:00 +0000;Mon, 07 Aug 2023 08:00:00 +0000;Mon, 31 Jul 2023 08:00:00 +0000;Mon, 24 Jul 2023 08:00:00 +0000;Mon, 17 Jul 2023 08:00:00 +0000;Mon, 10 Jul 2023 08:00:00 +0000;Mon, 03 Jul 2023 08:00:00 +0000;Mon, 26 Jun 2023 08:00:00 +0000;Mon, 19 Jun 2023 08:00:00 +0000;Mon, 12 Jun 2023 08:00:00 +0000;Mon, 05 Jun 2023 08:00:00 +0000;Mon, 29 May 2023 08:00:00 +0000;Mon, 22 May 2023 08:00:00 +0000;Mon, 15 May 2023 08:00:00 +0000;Mon, 08 May 2023 08:00:00 +0000;Mon, 01 May 2023 08:00:00 +0000;Mon, 24 Apr 2023 08:00:00 +0000;Mon, 17 Apr 2023 08:00:00 +0000;Mon, 10 Apr 2023 08:00:00 +0000;Mon, 03 Apr 2023 08:00:00 +0000;Tue, 28 Mar 2023 08:00:00 +0000;Mon, 20 Mar 2023 08:00:00 +0000;Mon, 13 Mar 2023 08:00:00 +0000;Mon, 06 Mar 2023 09:00:00 +0000;Mon, 27 Feb 2023 09:00:00 +0000
+Fri, 16 Feb 2024 10:00:00 -0000;Wed, 14 Feb 2024 08:00:00 -0000;Fri, 09 Feb 2024 10:00:00 -0000;Wed, 07 Feb 2024 08:00:00 -0000;Fri, 02 Feb 2024 10:00:00 -0000;Wed, 31 Jan 2024 08:00:00 -0000;Wed, 24 Jan 2024 08:00:00 -0000;Wed, 17 Jan 2024 08:00:00 -0000;Wed, 10 Jan 2024 08:00:00 -0000;Wed, 03 Jan 2024 08:00:00 -0000;Wed, 27 Dec 2023 08:00:00 -0000;Wed, 20 Dec 2023 08:00:00 -0000;Wed, 13 Dec 2023 08:00:00 -0000;Wed, 06 Dec 2023 08:00:00 -0000;Wed, 29 Nov 2023 08:00:00 -0000;Wed, 22 Nov 2023 08:00:00 -0000;Wed, 15 Nov 2023 08:00:00 -0000;Wed, 08 Nov 2023 08:00:00 -0000;Wed, 01 Nov 2023 07:00:00 -0000;Wed, 25 Oct 2023 07:00:00 -0000;Wed, 18 Oct 2023 07:00:00 -0000;Wed, 11 Oct 2023 07:00:00 -0000;Wed, 04 Oct 2023 07:00:00 -0000;Wed, 27 Sep 2023 10:00:00 -0000;Wed, 27 Sep 2023 07:00:00 -0000;Fri, 22 Sep 2023 07:00:00 -0000;Wed, 20 Sep 2023 07:00:00 -0000;Wed, 13 Sep 2023 07:00:00 -0000;Wed, 06 Sep 2023 07:00:00 -0000;Wed, 30 Aug 2023 07:00:00 -0000;Wed, 23 Aug 2023 07:00:00 -0000;Wed, 16 Aug 2023 07:00:00 -0000;Wed, 09 Aug 2023 07:00:00 -0000;Wed, 02 Aug 2023 07:00:00 -0000;Wed, 26 Jul 2023 07:00:00 -0000;Wed, 19 Jul 2023 07:00:00 -0000;Wed, 12 Jul 2023 07:00:00 -0000;Wed, 05 Jul 2023 07:00:00 -0000;Wed, 28 Jun 2023 07:00:00 -0000;Wed, 21 Jun 2023 07:00:00 -0000;Wed, 14 Jun 2023 07:00:00 -0000;Wed, 07 Jun 2023 07:00:00 -0000;Wed, 31 May 2023 07:00:00 -0000;Wed, 24 May 2023 07:00:00 -0000;Wed, 17 May 2023 07:00:00 -0000;Wed, 10 May 2023 07:00:00 -0000;Wed, 03 May 2023 07:00:00 -0000;Wed, 26 Apr 2023 07:00:00 -0000;Wed, 19 Apr 2023 07:00:00 -0000;Wed, 12 Apr 2023 07:00:00 -0000
+Wed, 14 Feb 2024 10:00:26 GMT;Tue, 06 Feb 2024 20:25:09 GMT
+Thu, 15 Feb 2024 06:01:00 -0000;Tue, 13 Feb 2024 06:01:00 -0000;Thu, 08 Feb 2024 06:01:00 -0000;Tue, 06 Feb 2024 06:01:00 -0000;Thu, 01 Feb 2024 06:01:00 -0000;Tue, 30 Jan 2024 06:01:00 -0000;Thu, 25 Jan 2024 06:01:00 -0000;Tue, 23 Jan 2024 06:01:00 -0000;Thu, 18 Jan 2024 06:01:00 -0000;Tue, 16 Jan 2024 06:01:00 -0000;Thu, 11 Jan 2024 06:01:00 -0000;Tue, 09 Jan 2024 06:01:00 -0000;Thu, 04 Jan 2024 06:01:00 -0000;Tue, 02 Jan 2024 06:01:00 -0000;Thu, 28 Dec 2023 06:01:00 -0000;Tue, 26 Dec 2023 06:01:00 -0000;Thu, 21 Dec 2023 06:01:00 -0000;Wed, 20 Dec 2023 06:01:00 -0000;Tue, 19 Dec 2023 07:01:00 -0000;Thu, 14 Dec 2023 06:01:00 -0000;Tue, 12 Dec 2023 06:01:00 -0000;Thu, 07 Dec 2023 06:01:00 -0000;Tue, 05 Dec 2023 06:01:00 -0000;Thu, 30 Nov 2023 06:10:00 -0000;Tue, 28 Nov 2023 06:10:00 -0000;Wed, 22 Nov 2023 06:01:00 -0000;Tue, 21 Nov 2023 07:01:00 -0000;Thu, 16 Nov 2023 06:01:00 -0000;Tue, 14 Nov 2023 06:01:00 -0000;Thu, 09 Nov 2023 06:01:00 -0000;Tue, 07 Nov 2023 07:01:00 -0000;Thu, 02 Nov 2023 10:00:00 -0000;Tue, 31 Oct 2023 09:00:00 -0000;Thu, 26 Oct 2023 05:01:00 -0000;Wed, 25 Oct 2023 04:01:00 -0000;Tue, 24 Oct 2023 09:00:00 -0000;Thu, 19 Oct 2023 12:00:00 -0000;Tue, 17 Oct 2023 07:01:00 -0000;Thu, 12 Oct 2023 07:01:00 -0000;Tue, 10 Oct 2023 07:01:00 -0000;Thu, 05 Oct 2023 07:01:00 -0000;Tue, 03 Oct 2023 07:01:00 -0000;Thu, 28 Sep 2023 04:51:00 -0000;Tue, 26 Sep 2023 04:58:00 -0000;Thu, 21 Sep 2023 05:05:00 -0000;Tue, 19 Sep 2023 05:09:00 -0000;Thu, 14 Sep 2023 05:13:00 -0000;Tue, 12 Sep 2023 07:01:00 -0000;Thu, 07 Sep 2023 05:22:00 -0000;Tue, 05 Sep 2023 05:26:00 -0000
+Fri, 16 Feb 2024 10:00:00 +0000;Tue, 13 Feb 2024 10:00:00 +0000;Fri, 9 Feb 2024 10:00:00 +0000;Tue, 6 Feb 2024 10:00:00 +0000;Fri, 2 Feb 2024 10:00:00 +0000;Tue, 30 Jan 2024 10:00:00 +0000;Fri, 26 Jan 2024 10:00:00 +0000;Tue, 23 Jan 2024 10:00:00 +0000;Fri, 19 Jan 2024 10:00:00 +0000;Tue, 16 Jan 2024 10:00:00 +0000;Fri, 12 Jan 2024 10:00:00 +0000;Tue, 9 Jan 2024 10:00:00 +0000;Fri, 5 Jan 2024 10:04:54 +0000;Tue, 2 Jan 2024 10:03:53 +0000;Fri, 29 Dec 2023 10:00:00 +0000;Tue, 26 Dec 2023 10:26:59 +0000;Fri, 22 Dec 2023 10:00:00 +0000;Tue, 19 Dec 2023 10:00:00 +0000;Fri, 15 Dec 2023 10:05:00 +0000;Tue, 12 Dec 2023 10:00:00 +0000;Fri, 8 Dec 2023 10:00:00 +0000;Tue, 5 Dec 2023 09:51:12 +0000;Fri, 1 Dec 2023 10:00:00 +0000;Tue, 28 Nov 2023 10:00:00 +0000;Fri, 24 Nov 2023 10:05:00 +0000;Tue, 21 Nov 2023 08:57:03 +0000;Fri, 17 Nov 2023 09:23:20 +0000;Tue, 14 Nov 2023 10:03:02 +0000;Fri, 10 Nov 2023 11:02:21 +0000;Tue, 7 Nov 2023 09:39:13 +0000;Fri, 3 Nov 2023 09:00:00 +0000;Tue, 31 Oct 2023 10:02:00 +0000;Fri, 27 Oct 2023 09:00:00 +0000;Tue, 24 Oct 2023 09:00:00 +0000;Fri, 20 Oct 2023 09:00:00 +0000;Tue, 17 Oct 2023 09:00:00 +0000;Fri, 13 Oct 2023 09:01:48 +0000;Tue, 10 Oct 2023 08:59:53 +0000;Fri, 6 Oct 2023 09:04:30 +0000;Tue, 3 Oct 2023 09:09:46 +0000;Fri, 29 Sep 2023 09:00:00 +0000;Tue, 26 Sep 2023 09:00:00 +0000;Fri, 22 Sep 2023 09:00:00 +0000;Tue, 19 Sep 2023 09:00:00 +0000;Fri, 15 Sep 2023 09:03:12 +0000;Tue, 12 Sep 2023 09:00:00 +0000;Fri, 8 Sep 2023 09:06:36 +0000;Tue, 5 Sep 2023 09:00:00 +0000;Fri, 1 Sep 2023 09:00:00 +0000;Tue, 29 Aug 2023 09:00:00 +0000
+Thu, 15 Feb 2024 08:00:00 -0000;Mon, 12 Feb 2024 08:00:00 -0000;Thu, 08 Feb 2024 08:00:00 -0000;Mon, 05 Feb 2024 08:00:00 -0000;Thu, 01 Feb 2024 08:00:00 -0000;Mon, 29 Jan 2024 08:00:00 -0000;Thu, 25 Jan 2024 08:00:00 -0000;Mon, 22 Jan 2024 08:00:00 -0000;Thu, 18 Jan 2024 08:00:00 -0000;Mon, 15 Jan 2024 08:00:00 -0000;Thu, 11 Jan 2024 08:00:00 -0000;Mon, 08 Jan 2024 08:00:00 -0000;Thu, 04 Jan 2024 08:00:00 -0000;Wed, 03 Jan 2024 20:34:00 -0000;Mon, 25 Dec 2023 08:00:00 -0000;Thu, 21 Dec 2023 08:00:00 -0000;Mon, 18 Dec 2023 08:00:00 -0000;Mon, 11 Dec 2023 08:00:00 -0000;Thu, 07 Dec 2023 08:00:00 -0000;Mon, 04 Dec 2023 08:00:00 -0000;Thu, 30 Nov 2023 08:00:00 -0000;Mon, 27 Nov 2023 08:00:00 -0000;Mon, 20 Nov 2023 08:00:00 -0000;Mon, 13 Nov 2023 08:00:00 -0000;Thu, 09 Nov 2023 08:00:00 -0000;Mon, 06 Nov 2023 08:00:00 -0000;Mon, 30 Oct 2023 07:00:00 -0000;Mon, 23 Oct 2023 07:00:00 -0000;Mon, 16 Oct 2023 07:00:00 -0000;Thu, 12 Oct 2023 07:00:00 -0000;Mon, 09 Oct 2023 07:00:00 -0000;Mon, 02 Oct 2023 07:00:00 -0000;Mon, 25 Sep 2023 07:00:00 -0000;Thu, 21 Sep 2023 07:00:00 -0000;Mon, 18 Sep 2023 07:00:00 -0000;Mon, 11 Sep 2023 07:00:00 -0000;Mon, 04 Sep 2023 07:00:00 -0000;Mon, 28 Aug 2023 07:00:00 -0000;Mon, 21 Aug 2023 07:00:00 -0000;Mon, 14 Aug 2023 07:00:00 -0000;Mon, 07 Aug 2023 07:00:00 -0000;Thu, 03 Aug 2023 07:00:00 -0000;Mon, 31 Jul 2023 07:00:00 -0000;Mon, 24 Jul 2023 07:00:00 -0000;Mon, 17 Jul 2023 07:00:00 -0000;Mon, 10 Jul 2023 07:00:00 -0000;Mon, 03 Jul 2023 07:00:00 -0000;Mon, 26 Jun 2023 07:00:00 -0000;Mon, 19 Jun 2023 07:30:00 -0000;Mon, 12 Jun 2023 07:30:00 -0000
+Sun, 18 Feb 2024 05:00:00 -0000;Thu, 15 Feb 2024 05:00:00 -0000;Sun, 11 Feb 2024 05:00:00 -0000;Sun, 04 Feb 2024 05:00:00 -0000;Sun, 28 Jan 2024 05:00:00 -0000;Sun, 21 Jan 2024 05:00:00 -0000;Thu, 18 Jan 2024 05:00:00 -0000;Sun, 14 Jan 2024 05:00:00 -0000;Sun, 07 Jan 2024 05:00:00 -0000;Sun, 31 Dec 2023 05:00:00 -0000;Sun, 24 Dec 2023 05:00:00 -0000;Sun, 17 Dec 2023 05:00:00 -0000;Thu, 14 Dec 2023 05:00:00 -0000;Sun, 10 Dec 2023 05:00:00 -0000;Thu, 07 Dec 2023 07:30:00 -0000;Sun, 26 Nov 2023 05:00:00 -0000;Sun, 19 Nov 2023 05:00:00 -0000;Thu, 16 Nov 2023 05:00:00 -0000;Sun, 12 Nov 2023 05:00:00 -0000;Sun, 05 Nov 2023 04:00:00 -0000;Sun, 29 Oct 2023 04:00:00 -0000;Sun, 22 Oct 2023 04:00:00 -0000;Sun, 15 Oct 2023 18:00:00 -0000;Thu, 12 Oct 2023 04:00:00 -0000;Sun, 08 Oct 2023 04:00:00 -0000;Sun, 01 Oct 2023 04:00:00 -0000;Sun, 24 Sep 2023 04:00:00 -0000;Sun, 17 Sep 2023 04:00:00 -0000;Thu, 14 Sep 2023 04:00:00 -0000;Sun, 10 Sep 2023 04:00:00 -0000;Sun, 03 Sep 2023 04:00:00 -0000;Sun, 27 Aug 2023 04:00:00 -0000;Sun, 20 Aug 2023 04:00:00 -0000;Thu, 17 Aug 2023 04:00:00 -0000;Sun, 13 Aug 2023 04:00:00 -0000;Sun, 06 Aug 2023 04:00:00 -0000;Sun, 30 Jul 2023 04:00:00 -0000;Thu, 27 Jul 2023 04:00:00 -0000;Sun, 23 Jul 2023 04:00:00 -0000;Sun, 16 Jul 2023 04:00:00 -0000;Sun, 09 Jul 2023 04:00:00 -0000;Sun, 02 Jul 2023 04:00:00 -0000;Thu, 29 Jun 2023 04:00:00 -0000;Sun, 25 Jun 2023 04:00:00 -0000;Sun, 18 Jun 2023 04:00:00 -0000;Thu, 15 Jun 2023 04:00:00 -0000;Sun, 11 Jun 2023 04:00:00 -0000;Sun, 04 Jun 2023 04:00:00 -0000;Sun, 28 May 2023 04:00:00 -0000;Sun, 21 May 2023 04:00:00 -0000
+Sat, 17 Feb 2024 09:00:00 -0000;Fri, 16 Feb 2024 09:00:00 -0000;Thu, 15 Feb 2024 09:00:00 -0000;Wed, 14 Feb 2024 09:00:00 -0000;Tue, 13 Feb 2024 09:00:00 -0000;Mon, 12 Feb 2024 09:00:00 -0000;Sun, 11 Feb 2024 09:00:00 -0000;Sat, 10 Feb 2024 09:00:00 -0000;Fri, 09 Feb 2024 09:00:00 -0000;Thu, 08 Feb 2024 09:00:00 -0000;Wed, 07 Feb 2024 09:00:00 -0000;Tue, 06 Feb 2024 09:00:00 -0000;Mon, 05 Feb 2024 09:00:00 -0000;Sun, 04 Feb 2024 09:00:00 -0000;Sat, 03 Feb 2024 09:00:00 -0000;Fri, 02 Feb 2024 09:00:00 -0000;Thu, 01 Feb 2024 09:00:00 -0000;Wed, 31 Jan 2024 09:00:00 -0000;Tue, 30 Jan 2024 09:00:00 -0000;Mon, 29 Jan 2024 09:00:00 -0000;Sun, 28 Jan 2024 10:00:00 -0000;Sat, 27 Jan 2024 09:00:00 -0000;Fri, 26 Jan 2024 09:00:00 -0000;Thu, 25 Jan 2024 09:00:00 -0000;Wed, 24 Jan 2024 09:00:00 -0000;Tue, 23 Jan 2024 05:00:00 -0000;Mon, 22 Jan 2024 09:00:00 -0000;Sun, 21 Jan 2024 09:00:00 -0000;Sat, 20 Jan 2024 09:00:00 -0000;Fri, 19 Jan 2024 09:00:00 -0000;Thu, 18 Jan 2024 09:00:00 -0000;Wed, 17 Jan 2024 09:00:00 -0000;Tue, 16 Jan 2024 09:00:00 -0000;Mon, 15 Jan 2024 09:00:00 -0000;Sun, 14 Jan 2024 09:00:00 -0000;Sat, 13 Jan 2024 09:00:00 -0000;Fri, 12 Jan 2024 09:00:00 -0000;Thu, 11 Jan 2024 09:00:00 -0000;Wed, 10 Jan 2024 09:00:00 -0000;Tue, 09 Jan 2024 09:00:00 -0000;Mon, 08 Jan 2024 09:00:00 -0000;Sun, 07 Jan 2024 09:00:00 -0000;Sat, 06 Jan 2024 09:00:00 -0000;Fri, 05 Jan 2024 09:00:00 -0000;Thu, 04 Jan 2024 09:00:00 -0000;Wed, 03 Jan 2024 09:00:00 -0000;Tue, 02 Jan 2024 09:00:00 -0000;Mon, 01 Jan 2024 09:00:00 -0000;Sun, 31 Dec 2023 10:00:00 -0000;Sat, 30 Dec 2023 10:00:00 -0000
+Thu, 15 Feb 2024 05:00:00 +0000;Wed, 14 Feb 2024 05:00:00 +0000;Wed, 7 Feb 2024 05:00:00 +0000;Thu, 25 Jan 2024 05:00:00 +0000;Thu, 28 Dec 2023 05:00:00 +0000;Thu, 30 Nov 2023 05:00:00 +0000;Thu, 26 Oct 2023 04:00:00 +0000;Thu, 28 Sep 2023 04:00:00 +0000;Thu, 24 Aug 2023 04:00:00 +0000;Thu, 27 Jul 2023 04:00:00 +0000;Thu, 29 Jun 2023 04:00:00 +0000;Thu, 11 May 2023 04:00:00 +0000;Thu, 27 Apr 2023 04:00:00 +0000;Thu, 30 Mar 2023 04:00:00 +0000;Tue, 28 Feb 2023 05:00:00 +0000;Thu, 12 Jan 2023 05:00:00 +0000;Mon, 19 Dec 2022 05:00:00 +0000;Thu, 1 Dec 2022 05:00:00 +0000;Thu, 8 Sep 2022 04:00:00 +0000;Wed, 7 Sep 2022 04:00:00 +0000;Thu, 1 Sep 2022 04:00:00 +0000;Wed, 31 Aug 2022 04:00:00 +0000;Thu, 25 Aug 2022 04:00:00 +0000;Wed, 24 Aug 2022 04:00:00 +0000;Thu, 18 Aug 2022 04:00:00 +0000;Wed, 17 Aug 2022 04:00:00 +0000;Thu, 11 Aug 2022 04:00:00 +0000;Wed, 10 Aug 2022 04:00:00 +0000;Thu, 4 Aug 2022 04:00:00 +0000;Wed, 3 Aug 2022 04:00:00 +0000;Thu, 28 Jul 2022 04:00:00 +0000;Wed, 27 Jul 2022 04:00:00 +0000;Thu, 21 Jul 2022 04:00:00 +0000;Wed, 20 Jul 2022 04:00:00 +0000;Tue, 12 Jul 2022 16:00:00 +0000
+Thu, 15 Feb 2024 05:00:00 +0000;Mon, 12 Feb 2024 05:00:00 +0000;Thu, 08 Feb 2024 05:00:00 +0000;Mon, 05 Feb 2024 05:00:00 +0000;Thu, 01 Feb 2024 05:00:00 +0000;Mon, 29 Jan 2024 17:17:54 +0000;Thu, 25 Jan 2024 05:00:00 +0000;Mon, 22 Jan 2024 05:00:00 +0000;Thu, 18 Jan 2024 05:00:00 +0000;Mon, 15 Jan 2024 05:00:00 +0000;Thu, 11 Jan 2024 05:00:00 +0000;Mon, 08 Jan 2024 05:00:00 +0000;Thu, 04 Jan 2024 05:00:00 +0000;Mon, 01 Jan 2024 05:00:00 +0000;Thu, 28 Dec 2023 05:00:00 +0000;Mon, 25 Dec 2023 05:00:00 +0000;Thu, 21 Dec 2023 05:00:00 +0000;Mon, 18 Dec 2023 05:00:00 +0000;Thu, 14 Dec 2023 05:00:00 +0000;Mon, 11 Dec 2023 05:00:00 +0000;Thu, 07 Dec 2023 05:00:00 +0000;Mon, 04 Dec 2023 05:00:00 +0000;Thu, 30 Nov 2023 05:00:00 +0000;Mon, 27 Nov 2023 05:00:00 +0000;Fri, 24 Nov 2023 05:00:00 +0000;Mon, 20 Nov 2023 05:00:00 +0000;Thu, 16 Nov 2023 05:00:00 +0000;Mon, 13 Nov 2023 05:00:00 +0000;Thu, 09 Nov 2023 05:00:00 +0000;Mon, 06 Nov 2023 05:00:00 +0000;Thu, 02 Nov 2023 04:00:00 +0000;Mon, 30 Oct 2023 04:00:00 +0000;Thu, 26 Oct 2023 04:00:00 +0000;Mon, 23 Oct 2023 04:00:00 +0000;Thu, 19 Oct 2023 04:00:00 +0000;Mon, 16 Oct 2023 04:00:00 +0000;Thu, 12 Oct 2023 04:00:00 +0000;Mon, 09 Oct 2023 04:00:00 +0000;Thu, 05 Oct 2023 04:00:00 +0000;Mon, 02 Oct 2023 04:00:00 +0000;Mon, 25 Sep 2023 04:05:00 +0000;Mon, 25 Sep 2023 04:00:00 +0000;Mon, 18 Sep 2023 04:00:00 +0000;Mon, 11 Sep 2023 04:00:00 +0000;Mon, 04 Sep 2023 04:00:00 +0000;Mon, 28 Aug 2023 04:00:00 +0000;Mon, 21 Aug 2023 04:00:00 +0000;Mon, 14 Aug 2023 04:00:00 +0000;Mon, 07 Aug 2023 04:00:00 +0000;Mon, 31 Jul 2023 04:00:00 +0000
+Sun, 18 Feb 2024 05:00:00 +0000;Thu, 15 Feb 2024 10:00:00 +0000;Tue, 13 Feb 2024 10:00:00 +0000;Sat, 10 Feb 2024 05:00:00 +0000;Wed, 07 Feb 2024 21:53:58 +0000;Sat, 03 Feb 2024 05:00:00 +0000;Thu, 01 Feb 2024 10:00:00 +0000;Tue, 30 Jan 2024 10:00:00 +0000;Sat, 27 Jan 2024 05:01:00 +0000;Thu, 25 Jan 2024 10:00:00 +0000;Tue, 23 Jan 2024 10:00:00 +0000;Sat, 20 Jan 2024 05:00:00 +0000;Thu, 18 Jan 2024 10:00:00 +0000;Tue, 16 Jan 2024 10:00:00 +0000;Sat, 13 Jan 2024 05:00:00 +0000;Thu, 11 Jan 2024 10:00:00 +0000;Tue, 09 Jan 2024 10:00:00 +0000;Sat, 06 Jan 2024 05:00:00 +0000;Thu, 04 Jan 2024 10:00:00 +0000;Tue, 02 Jan 2024 10:00:00 +0000;Thu, 28 Dec 2023 10:00:00 +0000;Tue, 26 Dec 2023 10:00:00 +0000;Fri, 22 Dec 2023 05:00:00 +0000;Thu, 21 Dec 2023 07:00:00 +0000;Tue, 19 Dec 2023 07:00:00 +0000;Sat, 16 Dec 2023 05:00:00 +0000;Thu, 14 Dec 2023 10:00:00 +0000;Tue, 12 Dec 2023 10:00:00 +0000;Sat, 09 Dec 2023 05:00:00 +0000;Thu, 07 Dec 2023 05:00:00 +0000;Tue, 05 Dec 2023 05:00:00 +0000;Thu, 30 Nov 2023 10:00:00 +0000;Tue, 28 Nov 2023 10:00:00 +0000;Sat, 25 Nov 2023 05:00:00 +0000;Thu, 23 Nov 2023 10:00:00 +0000;Tue, 21 Nov 2023 10:00:00 +0000;Sat, 18 Nov 2023 05:01:00 +0000;Thu, 16 Nov 2023 10:00:00 +0000;Tue, 14 Nov 2023 10:00:00 +0000;Sat, 11 Nov 2023 05:00:00 +0000;Thu, 09 Nov 2023 10:00:00 +0000;Tue, 07 Nov 2023 10:00:00 +0000;Sat, 04 Nov 2023 04:00:00 +0000;Thu, 02 Nov 2023 09:00:00 +0000;Tue, 31 Oct 2023 09:00:00 +0000;Sat, 28 Oct 2023 04:00:00 +0000;Thu, 26 Oct 2023 09:00:00 +0000;Tue, 24 Oct 2023 09:00:00 +0000;Sat, 21 Oct 2023 04:00:00 +0000;Thu, 19 Oct 2023 09:00:00 +0000
+Fri, 16 Feb 2024 16:54:00 +0000;Fri, 09 Feb 2024 16:54:00 +0000;Fri, 02 Feb 2024 15:46:00 +0000;Fri, 26 Jan 2024 16:37:00 +0000;Fri, 19 Jan 2024 16:07:00 +0000;Fri, 12 Jan 2024 16:41:00 +0000;Fri, 05 Jan 2024 17:03:00 +0000;Fri, 29 Dec 2023 18:06:00 +0000;Fri, 22 Dec 2023 17:45:00 +0000;Fri, 15 Dec 2023 16:54:00 +0000;Fri, 08 Dec 2023 18:04:00 +0000;Fri, 01 Dec 2023 17:26:00 +0000;Fri, 24 Nov 2023 16:31:00 +0000;Fri, 17 Nov 2023 13:20:00 +0000;Fri, 10 Nov 2023 17:34:00 +0000;Fri, 03 Nov 2023 15:37:00 +0000;Fri, 27 Oct 2023 17:33:00 +0000;Fri, 20 Oct 2023 10:00:00 +0000;Fri, 13 Oct 2023 11:00:00 +0000;Fri, 06 Oct 2023 17:01:00 +0000;Fri, 29 Sep 2023 17:42:00 +0000;Fri, 22 Sep 2023 18:23:00 +0000;Fri, 15 Sep 2023 17:44:00 +0000;Fri, 08 Sep 2023 16:52:00 +0000;Fri, 01 Sep 2023 16:33:00 +0000;Fri, 25 Aug 2023 16:39:00 +0000;Fri, 18 Aug 2023 15:51:00 +0000;Fri, 11 Aug 2023 15:50:00 +0000;Fri, 04 Aug 2023 17:14:00 +0000;Fri, 28 Jul 2023 17:24:00 +0000;Fri, 21 Jul 2023 11:43:00 +0000;Fri, 14 Jul 2023 15:39:00 +0000;Fri, 07 Jul 2023 10:00:00 +0000;Fri, 30 Jun 2023 18:06:00 +0000;Fri, 23 Jun 2023 17:24:00 +0000;Fri, 16 Jun 2023 16:49:00 +0000;Fri, 09 Jun 2023 18:02:00 +0000;Fri, 02 Jun 2023 15:57:00 +0000;Fri, 26 May 2023 15:30:00 +0000;Fri, 19 May 2023 15:06:00 +0000;Fri, 12 May 2023 18:55:00 +0000;Fri, 05 May 2023 16:16:00 +0000;Fri, 28 Apr 2023 17:46:00 +0000;Fri, 21 Apr 2023 17:37:00 +0000;Fri, 14 Apr 2023 18:22:00 +0000;Fri, 07 Apr 2023 17:18:00 +0000;Fri, 31 Mar 2023 18:07:00 +0000;Fri, 24 Mar 2023 17:23:00 +0000;Fri, 17 Mar 2023 16:53:00 +0000;Fri, 10 Mar 2023 17:53:00 +0000
+Thu, 15 Feb 2024 11:19:03 -0000;Mon, 12 Feb 2024 03:11:26 -0000;Thu, 08 Feb 2024 23:20:20 -0000;Mon, 05 Feb 2024 02:00:16 -0000;Fri, 02 Feb 2024 00:01:33 -0000;Sun, 28 Jan 2024 20:52:00 -0000;Thu, 25 Jan 2024 02:03:00 -0000;Fri, 19 Jan 2024 00:44:00 -0000;Tue, 16 Jan 2024 01:33:02 -0000;Fri, 12 Jan 2024 18:22:57 -0000;Sun, 07 Jan 2024 23:49:50 -0000;Fri, 05 Jan 2024 01:11:00 -0000;Mon, 01 Jan 2024 18:31:54 -0000;Wed, 27 Dec 2023 18:11:35 -0000;Wed, 20 Dec 2023 21:23:00 -0000;Mon, 18 Dec 2023 01:12:41 -0000;Sat, 16 Dec 2023 01:12:45 -0000;Sun, 10 Dec 2023 15:34:40 -0000;Thu, 07 Dec 2023 16:04:00 -0000;Sun, 03 Dec 2023 23:17:26 -0000;Wed, 29 Nov 2023 18:25:00 -0000;Thu, 23 Nov 2023 15:00:04 -0000;Mon, 20 Nov 2023 23:23:00 -0000;Wed, 15 Nov 2023 17:56:00 -0000;Sun, 12 Nov 2023 16:32:52 -0000;Thu, 09 Nov 2023 14:05:31 -0000;Sun, 05 Nov 2023 22:46:38 -0000;Wed, 01 Nov 2023 22:02:31 -0000;Mon, 30 Oct 2023 18:08:36 -0000;Wed, 25 Oct 2023 23:10:43 -0000;Mon, 23 Oct 2023 10:34:22 -0000;Wed, 18 Oct 2023 16:45:00 -0000;Sun, 15 Oct 2023 21:24:10 -0000;Wed, 11 Oct 2023 16:19:06 -0000;Mon, 09 Oct 2023 18:14:10 -0000;Wed, 04 Oct 2023 20:30:47 -0000;Sun, 01 Oct 2023 13:44:30 -0000;Wed, 27 Sep 2023 17:45:21 -0000;Sun, 24 Sep 2023 16:01:00 -0000;Thu, 21 Sep 2023 22:35:00 -0000;Sun, 17 Sep 2023 09:50:48 -0000;Thu, 14 Sep 2023 15:19:40 -0000;Sun, 10 Sep 2023 20:29:36 -0000;Wed, 06 Sep 2023 22:36:25 -0000;Mon, 04 Sep 2023 15:16:50 -0000;Wed, 30 Aug 2023 16:52:15 -0000;Sun, 27 Aug 2023 17:30:00 -0000;Wed, 23 Aug 2023 13:13:31 -0000;Sun, 20 Aug 2023 15:21:50 -0000;Wed, 16 Aug 2023 17:00:50 -0000
+Thu, 08 Feb 2024 14:16:23 +0000;Thu, 11 Jan 2024 09:00:03 +0000;Wed, 20 Dec 2023 08:00:03 +0000;Fri, 03 Nov 2023 08:00:03 +0000;Wed, 20 Sep 2023 18:19:07 +0000;Wed, 09 Aug 2023 21:36:43 +0000;Wed, 26 Jul 2023 21:09:20 +0000;Wed, 12 Jul 2023 08:00:03 +0000;Wed, 21 Jun 2023 20:23:23 +0000;Wed, 14 Jun 2023 15:06:04 +0000;Wed, 24 May 2023 08:00:03 +0000;Wed, 10 May 2023 08:00:02 +0000;Thu, 20 Apr 2023 08:00:03 +0000;Wed, 05 Apr 2023 08:00:00 +0000;Wed, 08 Mar 2023 08:00:03 +0000;Wed, 22 Feb 2023 08:00:02 +0000;Wed, 08 Feb 2023 08:00:02 +0000;Thu, 26 Jan 2023 15:22:05 +0000;Wed, 11 Jan 2023 08:00:02 +0000;Tue, 20 Dec 2022 17:00:00 +0000;Wed, 30 Nov 2022 08:00:00 +0000;Wed, 09 Nov 2022 09:00:00 +0000;Wed, 26 Oct 2022 08:00:00 +0000;Tue, 11 Oct 2022 19:20:47 +0000
+Fri, 16 Feb 2024 20:54:56 +0000;Thu, 15 Feb 2024 20:44:50 +0000;Wed, 14 Feb 2024 19:54:13 +0000;Tue, 13 Feb 2024 19:30:00 +0000;Mon, 12 Feb 2024 19:53:32 +0000;Fri, 09 Feb 2024 20:47:41 +0000;Thu, 08 Feb 2024 21:58:53 +0000;Wed, 07 Feb 2024 20:07:45 +0000;Tue, 06 Feb 2024 19:33:29 +0000;Mon, 05 Feb 2024 19:41:06 +0000;Fri, 02 Feb 2024 19:14:01 +0000;Thu, 01 Feb 2024 19:45:33 +0000;Wed, 31 Jan 2024 19:49:15 +0000;Tue, 30 Jan 2024 19:55:19 +0000;Mon, 29 Jan 2024 19:25:22 +0000;Fri, 26 Jan 2024 19:55:40 +0000;Thu, 25 Jan 2024 19:37:50 +0000;Wed, 24 Jan 2024 19:30:00 +0000;Tue, 23 Jan 2024 20:06:25 +0000;Mon, 22 Jan 2024 19:37:22 +0000;Fri, 19 Jan 2024 19:30:00 +0000;Thu, 18 Jan 2024 20:04:19 +0000;Wed, 17 Jan 2024 19:30:00 +0000;Tue, 16 Jan 2024 19:46:24 +0000;Mon, 15 Jan 2024 20:06:45 +0000;Fri, 12 Jan 2024 19:30:00 +0000;Thu, 11 Jan 2024 19:54:29 +0000;Wed, 10 Jan 2024 19:17:38 +0000;Tue, 09 Jan 2024 19:22:40 +0000;Mon, 08 Jan 2024 19:35:41 +0000;Fri, 05 Jan 2024 19:46:16 +0000;Thu, 04 Jan 2024 21:08:23 +0000;Wed, 03 Jan 2024 19:30:00 +0000;Tue, 02 Jan 2024 19:58:18 +0000;Fri, 22 Dec 2023 19:31:26 +0000;Thu, 21 Dec 2023 19:25:37 +0000;Wed, 20 Dec 2023 19:32:34 +0000;Tue, 19 Dec 2023 19:30:00 +0000;Mon, 18 Dec 2023 19:56:52 +0000;Fri, 15 Dec 2023 20:59:22 +0000;Thu, 14 Dec 2023 20:31:04 +0000;Wed, 13 Dec 2023 19:51:47 +0000;Tue, 12 Dec 2023 20:18:27 +0000;Mon, 11 Dec 2023 20:10:33 +0000;Fri, 08 Dec 2023 19:30:00 +0000;Thu, 07 Dec 2023 19:27:35 +0000;Wed, 06 Dec 2023 19:30:00 +0000;Tue, 05 Dec 2023 19:50:29 +0000;Mon, 04 Dec 2023 20:33:39 +0000;Fri, 01 Dec 2023 19:30:00 +0000
+Mon, 12 Feb 2024 08:02:00 -0000;Mon, 12 Feb 2024 08:01:00 -0000;Mon, 05 Feb 2024 08:02:00 -0000;Mon, 05 Feb 2024 08:01:00 -0000;Mon, 29 Jan 2024 08:02:00 -0000;Mon, 29 Jan 2024 08:01:00 -0000;Thu, 20 Jul 2023 07:01:00 -0000;Tue, 27 Jun 2023 07:01:00 -0000
+Wed, 14 Feb 2024 05:05:00 +0000;Wed, 7 Feb 2024 05:05:00 +0000;Mon, 5 Feb 2024 08:00:00 +0000;Wed, 31 Jan 2024 05:05:00 +0000;Mon, 29 Jan 2024 08:00:00 +0000;Wed, 24 Jan 2024 05:05:00 +0000;Wed, 17 Jan 2024 05:05:00 +0000;Wed, 10 Jan 2024 05:05:00 +0000;Wed, 3 Jan 2024 05:05:00 +0000;Wed, 27 Dec 2023 05:05:00 +0000;Wed, 20 Dec 2023 05:05:00 +0000;Wed, 13 Dec 2023 05:05:00 +0000;Mon, 11 Dec 2023 05:05:00 +0000;Wed, 6 Dec 2023 05:05:00 +0000;Wed, 29 Nov 2023 05:05:00 +0000;Wed, 22 Nov 2023 05:05:00 +0000;Wed, 15 Nov 2023 05:05:00 +0000;Wed, 8 Nov 2023 05:05:00 +0000;Wed, 1 Nov 2023 04:05:00 +0000;Wed, 25 Oct 2023 04:05:00 +0000;Wed, 18 Oct 2023 04:05:00 +0000;Wed, 11 Oct 2023 04:05:00 +0000;Wed, 4 Oct 2023 04:05:00 +0000;Wed, 27 Sep 2023 04:05:00 +0000;Wed, 20 Sep 2023 04:05:00 +0000;Wed, 13 Sep 2023 04:05:00 +0000;Wed, 6 Sep 2023 04:05:00 +0000;Wed, 30 Aug 2023 04:05:00 +0000;Wed, 23 Aug 2023 04:05:00 +0000;Wed, 16 Aug 2023 04:05:00 +0000;Wed, 9 Aug 2023 04:05:00 +0000;Wed, 2 Aug 2023 04:05:00 +0000;Wed, 26 Jul 2023 04:05:00 +0000;Fri, 21 Jul 2023 01:00:00 +0000;Wed, 12 Jul 2023 04:05:00 +0000;Wed, 5 Jul 2023 04:05:00 +0000;Wed, 28 Jun 2023 04:05:00 +0000;Wed, 21 Jun 2023 04:05:00 +0000;Wed, 14 Jun 2023 04:05:00 +0000;Wed, 7 Jun 2023 04:05:00 +0000;Wed, 31 May 2023 04:05:00 +0000;Wed, 24 May 2023 04:05:00 +0000;Wed, 17 May 2023 04:05:00 +0000;Wed, 10 May 2023 04:05:00 +0000;Fri, 5 May 2023 04:05:00 +0000;Wed, 3 May 2023 04:05:00 +0000;Wed, 26 Apr 2023 04:05:00 +0000;Wed, 19 Apr 2023 04:05:00 +0000;Wed, 12 Apr 2023 04:05:00 +0000;Wed, 5 Apr 2023 04:05:00 +0000
+Mon, 12 Feb 2024 05:30:00 -0600;Mon, 05 Feb 2024 05:30:00 -0600;Mon, 29 Jan 2024 05:30:00 -0600;Mon, 22 Jan 2024 05:30:00 -0600;Mon, 15 Jan 2024 05:00:00 -0600;Mon, 08 Jan 2024 05:00:00 -0600;Thu, 04 Jan 2024 09:00:00 -0600;Mon, 01 Jan 2024 09:00:00 -0600
+Sat, 17 Feb 2024 00:45:00 -0000;Thu, 15 Feb 2024 01:45:00 -0000;Sat, 10 Feb 2024 00:45:00 -0000;Thu, 08 Feb 2024 01:45:00 -0000;Sat, 03 Feb 2024 00:45:00 -0000;Thu, 01 Feb 2024 01:45:00 -0000;Sat, 27 Jan 2024 00:45:00 -0000;Thu, 25 Jan 2024 01:45:00 -0000;Sat, 20 Jan 2024 00:45:00 -0000;Thu, 18 Jan 2024 01:45:00 -0000;Sat, 13 Jan 2024 00:45:00 -0000;Thu, 11 Jan 2024 01:45:00 -0000;Sat, 06 Jan 2024 00:45:00 -0000;Thu, 04 Jan 2024 01:45:00 -0000;Sat, 30 Dec 2023 00:45:00 -0000;Thu, 28 Dec 2023 01:45:00 -0000;Sat, 23 Dec 2023 00:45:00 -0000;Thu, 21 Dec 2023 01:45:00 -0000;Sat, 16 Dec 2023 00:45:00 -0000;Thu, 14 Dec 2023 01:45:00 -0000;Sat, 09 Dec 2023 00:45:00 -0000;Thu, 07 Dec 2023 01:45:00 -0000;Sat, 02 Dec 2023 00:45:00 -0000;Thu, 30 Nov 2023 01:45:00 -0000;Sat, 25 Nov 2023 00:45:00 -0000;Thu, 23 Nov 2023 01:45:00 -0000;Sat, 18 Nov 2023 00:45:00 -0000;Thu, 16 Nov 2023 01:45:00 -0000;Sat, 11 Nov 2023 00:45:00 -0000;Thu, 09 Nov 2023 01:45:00 -0000;Fri, 03 Nov 2023 23:45:00 -0000;Thu, 02 Nov 2023 00:45:00 -0000;Fri, 27 Oct 2023 23:45:00 -0000;Thu, 26 Oct 2023 00:45:00 -0000;Fri, 20 Oct 2023 23:45:00 -0000;Thu, 19 Oct 2023 00:45:00 -0000;Fri, 13 Oct 2023 23:45:00 -0000;Thu, 12 Oct 2023 00:45:00 -0000;Fri, 06 Oct 2023 23:45:00 -0000;Thu, 05 Oct 2023 00:45:00 -0000;Fri, 29 Sep 2023 23:45:00 -0000;Thu, 28 Sep 2023 00:45:00 -0000;Fri, 22 Sep 2023 23:45:00 -0000;Thu, 21 Sep 2023 00:45:00 -0000;Sun, 17 Sep 2023 22:00:00 -0000;Fri, 15 Sep 2023 23:45:00 -0000;Thu, 14 Sep 2023 00:45:00 -0000;Fri, 08 Sep 2023 23:45:00 -0000;Thu, 07 Sep 2023 00:45:00 -0000;Fri, 01 Sep 2023 23:45:00 -0000
+Sat, 17 Feb 2024 07:54:55 +0000;Sat, 10 Feb 2024 07:34:04 +0000;Sat, 03 Feb 2024 08:27:32 +0000;Sat, 02 Dec 2023 11:11:30 +0000;Sat, 25 Nov 2023 08:01:10 +0000;Sat, 18 Nov 2023 10:03:01 +0000;Sat, 11 Nov 2023 10:03:57 +0000;Sat, 04 Nov 2023 07:30:00 +0000;Sat, 28 Oct 2023 07:12:48 +0000;Sat, 21 Oct 2023 08:42:41 +0000;Sat, 14 Oct 2023 07:30:11 +0000;Sat, 07 Oct 2023 08:10:48 +0000;Sat, 30 Sep 2023 08:16:30 +0000;Fri, 22 Sep 2023 20:15:00 +0000;Sat, 16 Sep 2023 08:06:04 +0000;Sat, 09 Sep 2023 07:56:17 +0000;Sat, 02 Sep 2023 08:16:28 +0000;Sat, 26 Aug 2023 08:14:08 +0000;Sat, 19 Aug 2023 07:52:10 +0000;Sat, 15 Jul 2023 07:15:00 +0000;Sat, 08 Jul 2023 06:33:31 +0000;Sat, 01 Jul 2023 09:22:52 +0000;Sat, 24 Jun 2023 09:14:04 +0000;Sat, 17 Jun 2023 10:06:14 +0000;Sat, 10 Jun 2023 08:01:00 +0000;Sat, 03 Jun 2023 09:43:58 +0000;Sat, 27 May 2023 07:00:00 +0000;Sat, 20 May 2023 08:01:56 +0000;Sat, 13 May 2023 09:04:09 +0000;Sat, 06 May 2023 08:05:42 +0000;Sat, 29 Apr 2023 07:57:57 +0000;Sat, 22 Apr 2023 06:40:08 +0000;Sat, 15 Apr 2023 08:11:13 +0000;Sat, 08 Apr 2023 07:00:00 +0000;Sat, 01 Apr 2023 07:00:00 +0000;Sat, 25 Mar 2023 08:41:49 +0000;Sat, 18 Mar 2023 10:05:09 +0000;Sat, 11 Mar 2023 15:07:00 +0000;Sat, 04 Mar 2023 08:00:00 +0000;Sat, 25 Feb 2023 08:55:08 +0000;Sat, 18 Feb 2023 08:07:00 +0000;Sat, 11 Feb 2023 10:04:11 +0000;Sat, 04 Feb 2023 10:10:05 +0000;Sat, 03 Dec 2022 09:37:54 +0000;Sat, 26 Nov 2022 09:50:26 +0000;Sat, 19 Nov 2022 09:14:33 +0000;Sat, 12 Nov 2022 09:42:40 +0000;Sat, 05 Nov 2022 09:56:57 +0000;Sat, 29 Oct 2022 08:30:51 +0000;Sat, 22 Oct 2022 08:10:01 +0000
+Wed, 14 Feb 2024 18:54:03 -0000;Wed, 04 Jan 2023 08:01:00 -0000;Wed, 28 Dec 2022 08:01:00 -0000;Wed, 21 Dec 2022 08:01:00 -0000;Wed, 14 Dec 2022 08:01:00 -0000;Wed, 07 Dec 2022 08:01:00 -0000;Wed, 30 Nov 2022 08:01:00 -0000;Wed, 23 Nov 2022 08:01:00 -0000;Wed, 16 Nov 2022 08:01:00 -0000;Wed, 09 Nov 2022 08:01:00 -0000;Wed, 02 Nov 2022 07:01:00 -0000;Wed, 26 Oct 2022 07:01:00 -0000;Wed, 19 Oct 2022 07:01:00 -0000;Mon, 17 Oct 2022 07:01:00 -0000;Wed, 12 Oct 2022 07:01:00 -0000;Wed, 05 Oct 2022 07:01:00 -0000;Wed, 28 Sep 2022 07:01:00 -0000;Wed, 21 Sep 2022 07:01:00 -0000;Wed, 25 May 2022 07:01:00 -0000;Wed, 18 May 2022 07:01:00 -0000;Wed, 11 May 2022 07:01:00 -0000;Wed, 04 May 2022 07:01:00 -0000;Wed, 27 Apr 2022 07:01:00 -0000;Wed, 20 Apr 2022 07:01:00 -0000;Wed, 06 Apr 2022 07:01:00 -0000;Wed, 30 Mar 2022 07:01:00 -0000;Wed, 23 Mar 2022 07:01:00 -0000;Wed, 09 Mar 2022 08:01:00 -0000;Wed, 02 Mar 2022 08:01:00 -0000;Wed, 23 Feb 2022 08:01:00 -0000;Wed, 16 Feb 2022 08:01:00 -0000;Mon, 14 Feb 2022 08:01:00 -0000;Wed, 09 Feb 2022 08:01:00 -0000;Wed, 26 Jan 2022 08:01:00 -0000;Wed, 15 Dec 2021 05:01:00 -0000;Wed, 08 Dec 2021 05:01:00 -0000;Wed, 01 Dec 2021 05:01:00 -0000;Wed, 24 Nov 2021 05:01:00 -0000;Wed, 17 Nov 2021 05:01:00 -0000;Wed, 10 Nov 2021 05:01:00 -0000;Wed, 03 Nov 2021 04:01:00 -0000;Wed, 27 Oct 2021 07:01:00 -0000;Wed, 20 Oct 2021 07:01:00 -0000;Wed, 13 Oct 2021 07:01:00 -0000;Wed, 06 Oct 2021 07:01:00 -0000;Wed, 29 Sep 2021 07:01:00 -0000;Wed, 22 Sep 2021 07:01:00 -0000;Wed, 15 Sep 2021 07:01:00 -0000;Wed, 28 Jul 2021 07:01:00 -0000;Wed, 21 Jul 2021 07:01:00 -0000
+Fri, 16 Feb 2024 23:41:00 +0000;Fri, 09 Feb 2024 19:42:00 +0000;Fri, 02 Feb 2024 19:59:00 +0000;Fri, 26 Jan 2024 20:11:00 +0000;Fri, 19 Jan 2024 21:56:00 +0000;Sat, 13 Jan 2024 22:39:00 +0000;Sat, 06 Jan 2024 05:48:00 +0000;Fri, 29 Dec 2023 17:00:00 +0000;Sat, 23 Dec 2023 02:26:00 +0000;Sat, 16 Dec 2023 00:37:00 +0000;Fri, 08 Dec 2023 00:11:00 +0000;Fri, 01 Dec 2023 17:13:00 +0000;Fri, 17 Nov 2023 08:20:00 +0000;Sat, 11 Nov 2023 01:02:00 +0000;Fri, 03 Nov 2023 08:33:00 +0000;Fri, 27 Oct 2023 19:48:00 +0000;Fri, 20 Oct 2023 07:23:00 +0000;Fri, 13 Oct 2023 16:00:00 +0000;Sat, 07 Oct 2023 03:35:00 +0000;Fri, 29 Sep 2023 19:50:00 +0000;Fri, 22 Sep 2023 22:51:00 +0000;Fri, 08 Sep 2023 20:23:00 +0000;Fri, 01 Sep 2023 12:00:00 +0000;Fri, 25 Aug 2023 23:56:00 +0000;Fri, 18 Aug 2023 21:58:00 +0000;Fri, 11 Aug 2023 06:23:00 +0000;Fri, 04 Aug 2023 20:16:00 +0000;Thu, 27 Jul 2023 22:08:00 +0000;Fri, 21 Jul 2023 21:53:00 +0000;Fri, 14 Jul 2023 17:02:00 +0000;Sun, 09 Jul 2023 17:22:00 +0000;Sat, 01 Jul 2023 01:32:00 +0000;Sat, 24 Jun 2023 01:14:00 +0000;Fri, 16 Jun 2023 20:55:00 +0000;Sat, 10 Jun 2023 17:00:00 +0000;Fri, 02 Jun 2023 20:36:00 +0000;Fri, 26 May 2023 20:19:00 +0000;Fri, 19 May 2023 21:12:00 +0000;Fri, 12 May 2023 19:50:00 +0000;Fri, 05 May 2023 21:44:00 +0000;Fri, 28 Apr 2023 19:07:00 +0000;Fri, 21 Apr 2023 21:07:00 +0000;Fri, 14 Apr 2023 08:39:00 +0000;Fri, 07 Apr 2023 09:17:00 +0000;Fri, 31 Mar 2023 08:07:00 +0000;Fri, 24 Mar 2023 09:29:00 +0000;Fri, 17 Mar 2023 05:16:00 +0000;Sat, 11 Mar 2023 15:46:00 +0000;Fri, 03 Mar 2023 18:43:00 +0000;Fri, 24 Feb 2023 20:41:00 +0000
+Sun, 18 Feb 2024 15:00:00 +0000;Thu, 30 Nov 2023 20:30:51 +0000
+Sun, 18 Feb 2024 10:00:00 +0000;Sat, 17 Feb 2024 10:00:00 +0000;Sat, 17 Feb 2024 00:00:00 +0000;Fri, 16 Feb 2024 21:39:45 +0000;Fri, 16 Feb 2024 10:00:00 +0000;Fri, 16 Feb 2024 00:00:00 +0000;Thu, 15 Feb 2024 21:59:34 +0000;Thu, 15 Feb 2024 10:00:00 +0000;Wed, 14 Feb 2024 23:20:00 +0000;Wed, 14 Feb 2024 21:50:03 +0000;Wed, 14 Feb 2024 10:00:00 +0000;Tue, 13 Feb 2024 23:20:00 +0000;Tue, 13 Feb 2024 21:24:48 +0000;Tue, 13 Feb 2024 10:00:00 +0000;Mon, 12 Feb 2024 23:30:00 +0000;Mon, 12 Feb 2024 21:52:53 +0000;Mon, 12 Feb 2024 10:00:00 +0000;Sun, 11 Feb 2024 10:00:00 +0000;Sat, 10 Feb 2024 10:00:00 +0000;Fri, 09 Feb 2024 23:20:00 +0000;Fri, 09 Feb 2024 21:48:57 +0000;Fri, 09 Feb 2024 10:00:00 +0000;Fri, 09 Feb 2024 01:00:00 +0000;Thu, 08 Feb 2024 23:05:53 +0000;Thu, 08 Feb 2024 21:44:56 +0000;Thu, 08 Feb 2024 10:00:00 +0000;Wed, 07 Feb 2024 23:30:00 +0000;Wed, 07 Feb 2024 22:20:20 +0000;Wed, 07 Feb 2024 10:00:00 +0000;Wed, 07 Feb 2024 00:13:45 +0000;Tue, 06 Feb 2024 20:40:51 +0000;Tue, 06 Feb 2024 10:00:00 +0000;Mon, 05 Feb 2024 23:20:00 +0000;Mon, 05 Feb 2024 22:05:26 +0000;Mon, 05 Feb 2024 10:00:00 +0000;Sun, 04 Feb 2024 10:00:00 +0000;Sat, 03 Feb 2024 10:00:00 +0000;Fri, 02 Feb 2024 23:00:00 +0000;Fri, 02 Feb 2024 21:48:48 +0000;Fri, 02 Feb 2024 10:00:00 +0000;Fri, 02 Feb 2024 01:25:12 +0000;Thu, 01 Feb 2024 23:00:00 +0000;Thu, 01 Feb 2024 21:54:15 +0000;Thu, 01 Feb 2024 00:35:25 +0000;Wed, 31 Jan 2024 23:30:00 +0000;Wed, 31 Jan 2024 22:07:23 +0000;Wed, 31 Jan 2024 10:00:00 +0000;Tue, 30 Jan 2024 23:40:05 +0000;Tue, 30 Jan 2024 21:20:41 +0000;Tue, 30 Jan 2024 10:00:00 +0000
+Fri, 16 Feb 2024 08:00:00 +0000;Wed, 14 Feb 2024 08:00:00 +0000;Mon, 12 Feb 2024 08:00:00 +0000;Fri, 9 Feb 2024 08:00:00 +0000;Wed, 7 Feb 2024 08:00:00 +0000;Mon, 5 Feb 2024 08:00:00 +0000;Fri, 2 Feb 2024 08:00:00 +0000;Wed, 31 Jan 2024 08:00:00 +0000;Mon, 29 Jan 2024 08:00:00 +0000;Sat, 27 Jan 2024 08:00:00 +0000;Fri, 26 Jan 2024 08:00:00 +0000;Wed, 24 Jan 2024 08:00:00 +0000;Mon, 22 Jan 2024 08:00:00 +0000;Fri, 19 Jan 2024 08:00:00 +0000;Wed, 17 Jan 2024 08:00:00 +0000;Mon, 15 Jan 2024 08:00:00 +0000;Sat, 13 Jan 2024 08:00:00 +0000;Fri, 12 Jan 2024 08:00:00 +0000;Wed, 10 Jan 2024 08:00:00 +0000;Mon, 8 Jan 2024 08:00:00 +0000;Fri, 5 Jan 2024 08:00:00 +0000;Wed, 3 Jan 2024 08:00:00 +0000;Mon, 1 Jan 2024 08:00:00 +0000;Sat, 30 Dec 2023 08:00:00 +0000;Fri, 29 Dec 2023 08:00:00 +0000;Wed, 27 Dec 2023 08:00:00 +0000;Mon, 25 Dec 2023 08:00:00 +0000;Fri, 22 Dec 2023 08:00:00 +0000;Wed, 20 Dec 2023 08:00:00 +0000;Mon, 18 Dec 2023 08:00:00 +0000;Sat, 16 Dec 2023 08:00:00 +0000;Fri, 15 Dec 2023 08:00:00 +0000;Wed, 13 Dec 2023 08:00:00 +0000;Mon, 11 Dec 2023 08:00:00 +0000;Fri, 8 Dec 2023 08:00:00 +0000;Wed, 6 Dec 2023 08:00:00 +0000;Mon, 4 Dec 2023 08:00:00 +0000;Sat, 2 Dec 2023 08:00:00 +0000;Fri, 1 Dec 2023 08:00:00 +0000;Wed, 29 Nov 2023 08:00:00 +0000;Mon, 27 Nov 2023 08:00:00 +0000;Fri, 24 Nov 2023 08:00:00 +0000;Wed, 22 Nov 2023 08:00:00 +0000;Mon, 20 Nov 2023 08:00:00 +0000;Sat, 18 Nov 2023 08:00:00 +0000;Fri, 17 Nov 2023 08:00:00 +0000;Wed, 15 Nov 2023 08:00:00 +0000;Mon, 13 Nov 2023 08:00:00 +0000;Fri, 10 Nov 2023 08:00:00 +0000;Wed, 8 Nov 2023 08:00:00 +0000
+Tue, 13 Feb 2024 06:00:00 -0000;Tue, 06 Feb 2024 06:00:00 -0000;Tue, 30 Jan 2024 06:00:00 -0000;Tue, 23 Jan 2024 06:00:00 -0000;Tue, 16 Jan 2024 06:00:00 -0000;Tue, 09 Jan 2024 06:00:00 -0000;Tue, 02 Jan 2024 06:00:00 -0000;Mon, 18 Dec 2023 05:00:00 -0000;Mon, 04 Dec 2023 14:00:00 -0000;Wed, 08 Nov 2023 21:37:00 -0000;Mon, 02 Oct 2023 13:00:00 -0000;Wed, 16 Aug 2023 23:00:00 -0000;Mon, 14 Aug 2023 07:00:00 -0000;Mon, 07 Aug 2023 07:00:00 -0000;Mon, 31 Jul 2023 07:00:00 -0000;Mon, 24 Jul 2023 07:00:00 -0000;Mon, 17 Jul 2023 07:00:00 -0000;Mon, 10 Jul 2023 07:00:00 -0000;Mon, 03 Jul 2023 07:00:00 -0000;Wed, 14 Jun 2023 07:00:00 -0000;Wed, 26 Apr 2023 04:30:00 -0000;Wed, 19 Apr 2023 04:30:00 -0000;Wed, 12 Apr 2023 04:30:00 -0000;Wed, 05 Apr 2023 04:30:00 -0000;Wed, 29 Mar 2023 04:30:00 -0000;Wed, 22 Mar 2023 05:30:00 -0000;Wed, 15 Mar 2023 05:30:00 -0000;Wed, 08 Mar 2023 05:30:00 -0000;Wed, 01 Mar 2023 06:00:00 -0000;Thu, 23 Feb 2023 21:16:00 -0000
+Thu, 15 Feb 2024 12:00:03 +0000;Thu, 08 Feb 2024 12:00:03 +0000;Tue, 06 Feb 2024 16:33:57 +0000
+Tue, 13 Feb 2024 08:00:00 +0000;Tue, 6 Feb 2024 08:00:00 +0000;Tue, 30 Jan 2024 08:00:00 +0000;Tue, 23 Jan 2024 08:00:00 +0000;Tue, 16 Jan 2024 08:00:00 +0000;Tue, 9 Jan 2024 08:00:00 +0000;Tue, 26 Dec 2023 08:00:00 +0000;Tue, 19 Dec 2023 08:00:00 +0000;Tue, 12 Dec 2023 08:00:00 +0000;Tue, 5 Dec 2023 08:00:00 +0000;Tue, 28 Nov 2023 08:00:00 +0000;Tue, 21 Nov 2023 08:00:00 +0000;Tue, 14 Nov 2023 08:00:00 +0000;Tue, 7 Nov 2023 08:00:00 +0000;Tue, 31 Oct 2023 07:00:00 +0000;Tue, 24 Oct 2023 07:00:00 +0000;Tue, 17 Oct 2023 07:00:00 +0000;Tue, 10 Oct 2023 07:00:00 +0000;Tue, 3 Oct 2023 07:00:00 +0000;Tue, 26 Sep 2023 07:00:00 +0000;Tue, 19 Sep 2023 07:00:00 +0000;Tue, 12 Sep 2023 07:00:00 +0000;Tue, 5 Sep 2023 07:00:00 +0000;Tue, 29 Aug 2023 12:04:08 +0000;Tue, 22 Aug 2023 07:00:00 +0000;Tue, 15 Aug 2023 07:00:00 +0000;Tue, 8 Aug 2023 07:00:00 +0000;Tue, 1 Aug 2023 07:00:00 +0000;Tue, 25 Jul 2023 07:00:00 +0000;Tue, 18 Jul 2023 07:00:00 +0000;Tue, 11 Jul 2023 07:00:00 +0000;Tue, 27 Jun 2023 07:00:00 +0000;Tue, 13 Jun 2023 07:00:00 +0000;Tue, 6 Jun 2023 07:00:00 +0000;Tue, 30 May 2023 07:00:00 +0000;Tue, 23 May 2023 07:00:00 +0000;Tue, 16 May 2023 07:00:00 +0000;Tue, 9 May 2023 07:00:00 +0000;Tue, 2 May 2023 07:00:00 +0000;Tue, 18 Apr 2023 07:00:00 +0000;Tue, 11 Apr 2023 07:00:00 +0000;Tue, 4 Apr 2023 07:00:00 +0000;Tue, 28 Mar 2023 07:00:00 +0000;Tue, 21 Mar 2023 07:00:00 +0000;Tue, 14 Mar 2023 07:00:00 +0000;Tue, 7 Mar 2023 08:00:00 +0000;Tue, 28 Feb 2023 08:00:00 +0000;Tue, 14 Feb 2023 08:00:00 +0000;Tue, 7 Feb 2023 08:00:00 +0000;Tue, 31 Jan 2023 08:00:00 +0000
+Sat, 10 Feb 2024 02:30:00 -0000;Mon, 05 Feb 2024 02:45:00 -0000;Mon, 29 Jan 2024 02:45:00 -0000;Mon, 22 Jan 2024 02:45:00 -0000;Mon, 15 Jan 2024 02:45:00 -0000;Tue, 09 Jan 2024 16:06:31 -0000
+Wed, 14 Feb 2024 11:00:00 +0000;Wed, 07 Feb 2024 11:00:00 +0000;Wed, 31 Jan 2024 11:00:00 +0000;Wed, 24 Jan 2024 11:00:00 +0000;Wed, 17 Jan 2024 11:00:00 +0000;Wed, 10 Jan 2024 11:00:00 +0000;Wed, 03 Jan 2024 12:45:00 +0000
+Thu, 15 Feb 2024 09:00:02 +0000;Thu, 08 Feb 2024 08:00:02 +0000;Thu, 01 Feb 2024 11:00:03 +0000;Thu, 25 Jan 2024 11:00:18 +0000;Thu, 18 Jan 2024 08:00:01 +0000;Thu, 11 Jan 2024 08:00:03 +0000;Thu, 04 Jan 2024 08:00:03 +0000;Thu, 28 Dec 2023 08:00:03 +0000;Thu, 21 Dec 2023 08:00:03 +0000;Thu, 14 Dec 2023 08:00:04 +0000;Thu, 07 Dec 2023 08:00:03 +0000;Thu, 30 Nov 2023 08:00:03 +0000;Thu, 16 Nov 2023 11:30:03 +0000;Thu, 09 Nov 2023 13:59:03 +0000;Wed, 01 Nov 2023 13:41:59 +0000
+Fri, 16 Feb 2024 22:05:48 +0000;Thu, 15 Feb 2024 00:34:16 +0000;Fri, 09 Feb 2024 23:13:45 +0000;Wed, 07 Feb 2024 23:45:25 +0000;Fri, 02 Feb 2024 22:53:29 +0000;Wed, 31 Jan 2024 23:43:22 +0000;Mon, 29 Jan 2024 22:37:03 +0000;Sat, 27 Jan 2024 01:01:02 +0000;Wed, 24 Jan 2024 08:00:30 +0000;Sat, 20 Jan 2024 02:10:26 +0000;Wed, 17 Jan 2024 23:17:47 +0000;Sat, 13 Jan 2024 00:54:02 +0000;Wed, 10 Jan 2024 22:16:22 +0000;Fri, 05 Jan 2024 22:26:04 +0000;Fri, 29 Dec 2023 22:45:39 +0000;Wed, 27 Dec 2023 08:00:00 +0000;Fri, 22 Dec 2023 22:25:41 +0000;Thu, 21 Dec 2023 00:35:54 +0000;Tue, 19 Dec 2023 00:58:12 +0000;Sat, 16 Dec 2023 02:31:16 +0000;Thu, 14 Dec 2023 02:46:07 +0000;Mon, 11 Dec 2023 20:03:40 +0000;Fri, 08 Dec 2023 23:28:31 +0000;Wed, 06 Dec 2023 23:01:57 +0000;Fri, 01 Dec 2023 23:11:04 +0000;Wed, 29 Nov 2023 23:44:37 +0000;Wed, 22 Nov 2023 23:33:32 +0000;Sat, 18 Nov 2023 00:48:46 +0000;Wed, 15 Nov 2023 23:33:53 +0000;Fri, 10 Nov 2023 23:54:07 +0000;Wed, 08 Nov 2023 23:38:36 +0000;Fri, 03 Nov 2023 21:45:05 +0000;Wed, 01 Nov 2023 23:25:48 +0000;Fri, 27 Oct 2023 22:23:43 +0000;Thu, 26 Oct 2023 00:08:11 +0000;Fri, 20 Oct 2023 23:47:08 +0000;Wed, 18 Oct 2023 21:33:41 +0000;Fri, 13 Oct 2023 23:26:29 +0000;Wed, 11 Oct 2023 20:22:40 +0000;Fri, 06 Oct 2023 18:48:33 +0000;Wed, 04 Oct 2023 23:28:41 +0000;Fri, 29 Sep 2023 21:18:51 +0000;Wed, 27 Sep 2023 21:18:11 +0000;Sat, 23 Sep 2023 03:34:53 +0000;Wed, 20 Sep 2023 21:41:25 +0000;Sat, 16 Sep 2023 00:11:27 +0000;Wed, 13 Sep 2023 21:50:02 +0000;Fri, 08 Sep 2023 21:00:48 +0000;Wed, 06 Sep 2023 21:48:18 +0000;Fri, 01 Sep 2023 22:18:41 +0000
+Fri, 16 Feb 2024 09:00:00 -0000;Tue, 13 Feb 2024 07:00:00 -0000;Fri, 09 Feb 2024 07:00:00 -0000;Tue, 06 Feb 2024 07:00:00 -0000;Fri, 02 Feb 2024 09:22:00 -0000;Tue, 30 Jan 2024 07:00:00 -0000;Fri, 26 Jan 2024 07:00:00 -0000;Tue, 23 Jan 2024 07:00:00 -0000;Fri, 19 Jan 2024 07:00:00 -0000;Tue, 16 Jan 2024 07:00:00 -0000;Fri, 12 Jan 2024 07:00:00 -0000;Tue, 09 Jan 2024 09:00:00 -0000;Fri, 05 Jan 2024 09:00:00 -0000;Wed, 03 Jan 2024 15:00:00 -0000;Fri, 29 Dec 2023 09:00:00 -0000;Tue, 26 Dec 2023 09:00:00 -0000;Fri, 22 Dec 2023 07:00:00 -0000;Tue, 19 Dec 2023 07:00:00 -0000;Fri, 15 Dec 2023 07:00:00 -0000;Tue, 12 Dec 2023 07:00:00 -0000;Fri, 08 Dec 2023 07:00:00 -0000;Tue, 05 Dec 2023 07:00:00 -0000;Fri, 01 Dec 2023 09:24:00 -0000;Tue, 28 Nov 2023 07:00:00 -0000;Fri, 24 Nov 2023 07:00:00 -0000;Tue, 21 Nov 2023 07:00:00 -0000;Fri, 17 Nov 2023 07:00:00 -0000;Tue, 14 Nov 2023 07:00:00 -0000;Fri, 10 Nov 2023 07:00:00 -0000;Tue, 07 Nov 2023 07:00:00 -0000;Fri, 03 Nov 2023 15:43:00 -0000;Tue, 31 Oct 2023 07:00:00 -0000;Fri, 27 Oct 2023 07:00:00 -0000;Tue, 24 Oct 2023 07:00:00 -0000;Fri, 20 Oct 2023 07:00:00 -0000;Tue, 17 Oct 2023 07:00:00 -0000;Fri, 13 Oct 2023 07:00:00 -0000;Tue, 10 Oct 2023 07:00:00 -0000;Fri, 06 Oct 2023 07:00:00 -0000;Tue, 03 Oct 2023 07:00:00 -0000;Fri, 29 Sep 2023 07:00:00 -0000;Tue, 26 Sep 2023 07:00:00 -0000;Fri, 22 Sep 2023 07:00:00 -0000;Tue, 19 Sep 2023 07:00:00 -0000;Fri, 15 Sep 2023 07:00:00 -0000;Tue, 12 Sep 2023 07:00:00 -0000;Fri, 08 Sep 2023 07:00:00 -0000;Tue, 05 Sep 2023 07:00:00 -0000;Fri, 01 Sep 2023 07:00:00 -0000;Tue, 29 Aug 2023 09:12:00 -0000
+
+
+Fri, 16 Feb 2024 05:00:00 -0000;Fri, 26 Jan 2024 17:00:00 -0000;Wed, 20 Dec 2023 05:00:00 -0000;Wed, 13 Dec 2023 05:00:00 -0000;Wed, 06 Dec 2023 05:00:00 -0000;Wed, 29 Nov 2023 05:00:00 -0000;Wed, 22 Nov 2023 05:00:00 -0000;Wed, 15 Nov 2023 05:00:00 -0000;Wed, 08 Nov 2023 05:00:00 -0000;Wed, 01 Nov 2023 04:00:00 -0000;Wed, 25 Oct 2023 04:00:00 -0000;Wed, 18 Oct 2023 04:00:00 -0000;Wed, 27 Sep 2023 04:00:00 -0000;Fri, 14 Jul 2023 04:00:00 -0000;Wed, 07 Jun 2023 04:00:00 -0000;Wed, 31 May 2023 04:00:00 -0000;Wed, 24 May 2023 04:00:00 -0000;Wed, 17 May 2023 04:00:00 -0000;Wed, 10 May 2023 04:00:00 -0000;Wed, 03 May 2023 04:00:00 -0000;Wed, 26 Apr 2023 04:00:00 -0000;Wed, 19 Apr 2023 04:00:00 -0000;Wed, 12 Apr 2023 04:00:00 -0000;Wed, 05 Apr 2023 04:00:00 -0000;Sun, 26 Feb 2023 03:00:00 -0000;Wed, 26 Oct 2022 04:00:00 -0000;Wed, 19 Oct 2022 04:00:00 -0000;Wed, 12 Oct 2022 04:00:00 -0000;Wed, 05 Oct 2022 04:00:00 -0000;Wed, 28 Sep 2022 04:00:00 -0000;Wed, 21 Sep 2022 04:00:00 -0000;Wed, 14 Sep 2022 04:00:00 -0000;Wed, 07 Sep 2022 04:00:00 -0000;Wed, 24 Aug 2022 04:00:00 -0000;Wed, 10 Aug 2022 04:00:00 -0000;Wed, 06 Jul 2022 04:00:00 -0000;Wed, 29 Jun 2022 04:00:00 -0000;Wed, 22 Jun 2022 04:00:00 -0000;Wed, 15 Jun 2022 04:00:00 -0000;Wed, 08 Jun 2022 04:00:00 -0000;Wed, 01 Jun 2022 04:00:00 -0000;Wed, 25 May 2022 04:00:00 -0000;Wed, 18 May 2022 04:00:00 -0000;Wed, 04 May 2022 04:00:00 -0000;Wed, 20 Apr 2022 04:00:00 -0000;Wed, 23 Feb 2022 05:00:00 -0000;Wed, 16 Feb 2022 05:00:00 -0000;Wed, 09 Feb 2022 05:00:00 -0000;Wed, 02 Feb 2022 05:00:00 -0000;Wed, 26 Jan 2022 05:00:00 -0000
+Wed, 14 Feb 2024 08:15:00 +0000;Sat, 10 Feb 2024 17:19:00 +0000
+Tue, 13 Feb 2024 17:55:01 +0000;Tue, 06 Feb 2024 21:00:00 +0000
+Mon, 12 Feb 2024 22:00:00 -0000;Wed, 07 Feb 2024 22:00:00 -0000;Wed, 31 Jan 2024 23:00:00 -0000;Wed, 24 Jan 2024 23:00:00 -0000;Wed, 17 Jan 2024 23:00:00 -0000;Wed, 10 Jan 2024 23:00:00 -0000;Thu, 28 Dec 2023 21:00:00 -0000;Fri, 22 Dec 2023 15:30:00 -0000;Thu, 21 Dec 2023 07:22:16 -0000
+Fri, 16 Feb 2024 18:49:37 +0000;Fri, 02 Feb 2024 00:04:50 +0000;Tue, 23 Jan 2024 17:06:47 +0000;Wed, 17 Jan 2024 16:51:44 +0000;Tue, 09 Jan 2024 22:35:21 +0000;Fri, 29 Dec 2023 21:03:57 +0000;Sun, 24 Dec 2023 21:27:55 +0000;Thu, 14 Dec 2023 18:57:48 +0000;Sat, 09 Dec 2023 21:21:58 +0000;Sun, 03 Dec 2023 17:37:26 +0000;Sat, 25 Nov 2023 21:11:31 +0000;Sat, 18 Nov 2023 14:05:32 +0000;Thu, 09 Nov 2023 19:03:46 +0000;Wed, 11 Oct 2023 20:21:10 +0000;Thu, 28 Sep 2023 21:15:22 +0000;Mon, 25 Sep 2023 01:12:01 +0000;Mon, 18 Sep 2023 01:07:29 +0000;Sun, 10 Sep 2023 20:21:44 +0000;Fri, 01 Sep 2023 19:10:20 +0000;Thu, 17 Aug 2023 20:37:40 +0000;Tue, 01 Aug 2023 18:49:08 +0000;Mon, 24 Jul 2023 15:32:40 +0000;Mon, 17 Jul 2023 15:44:20 +0000;Wed, 12 Jul 2023 18:07:31 +0000;Thu, 06 Jul 2023 22:07:19 +0000;Fri, 30 Jun 2023 01:16:21 +0000;Thu, 22 Jun 2023 02:04:50 +0000;Sun, 18 Jun 2023 22:42:02 +0000;Tue, 13 Jun 2023 18:26:43 +0000;Thu, 08 Jun 2023 22:49:41 +0000;Mon, 05 Jun 2023 17:10:35 +0000;Fri, 02 Jun 2023 21:20:17 +0000;Sun, 28 May 2023 15:29:58 +0000;Wed, 24 May 2023 15:27:23 +0000;Thu, 18 May 2023 21:18:08 +0000;Tue, 16 May 2023 01:18:32 +0000;Tue, 09 May 2023 17:12:11 +0000;Sat, 06 May 2023 17:39:54 +0000;Fri, 28 Apr 2023 19:13:09 +0000;Fri, 21 Apr 2023 22:21:23 +0000;Sun, 16 Apr 2023 19:51:34 +0000;Thu, 13 Apr 2023 16:26:42 +0000;Mon, 10 Apr 2023 02:14:34 +0000;Tue, 04 Apr 2023 18:50:10 +0000;Thu, 30 Mar 2023 15:14:29 +0000;Sat, 25 Mar 2023 18:04:11 +0000;Tue, 21 Mar 2023 23:02:22 +0000;Tue, 14 Mar 2023 17:19:34 +0000;Fri, 10 Mar 2023 17:16:27 +0000;Mon, 06 Mar 2023 18:33:58 +0000
+Thu, 08 Feb 2024 08:01:00 +0000;Thu, 01 Feb 2024 17:07:00 +0000
+Sat, 17 Feb 2024 16:00:00 +0000;Wed, 14 Feb 2024 19:39:24 +0000;Wed, 14 Feb 2024 04:16:28 +0000;Tue, 13 Feb 2024 19:41:56 +0000;Mon, 12 Feb 2024 19:06:08 +0000;Sat, 10 Feb 2024 16:00:00 +0000;Fri, 9 Feb 2024 19:27:28 +0000;Thu, 8 Feb 2024 19:30:00 +0000;Wed, 7 Feb 2024 19:30:00 +0000;Tue, 6 Feb 2024 19:30:00 +0000;Mon, 5 Feb 2024 19:30:00 +0000;Sat, 3 Feb 2024 16:00:00 +0000;Fri, 2 Feb 2024 19:30:00 +0000;Thu, 1 Feb 2024 19:30:00 +0000;Wed, 31 Jan 2024 19:28:33 +0000;Tue, 30 Jan 2024 19:32:37 +0000;Mon, 29 Jan 2024 19:30:00 +0000;Sat, 27 Jan 2024 16:00:00 +0000;Fri, 26 Jan 2024 19:30:00 +0000;Thu, 25 Jan 2024 19:27:33 +0000;Wed, 24 Jan 2024 19:30:00 +0000;Tue, 23 Jan 2024 19:30:00 +0000;Mon, 22 Jan 2024 19:30:00 +0000;Sat, 20 Jan 2024 16:00:00 +0000;Fri, 19 Jan 2024 19:30:00 +0000;Thu, 18 Jan 2024 19:30:00 +0000;Wed, 17 Jan 2024 19:34:54 +0000;Tue, 16 Jan 2024 19:30:00 +0000;Mon, 15 Jan 2024 20:17:23 +0000;Sat, 13 Jan 2024 16:00:00 +0000;Fri, 12 Jan 2024 19:30:00 +0000;Thu, 11 Jan 2024 19:30:00 +0000;Wed, 10 Jan 2024 19:30:00 +0000;Tue, 9 Jan 2024 19:30:00 +0000;Mon, 8 Jan 2024 19:30:00 +0000;Sat, 6 Jan 2024 16:00:00 +0000;Fri, 5 Jan 2024 19:30:00 +0000;Thu, 4 Jan 2024 19:30:00 +0000;Wed, 3 Jan 2024 19:30:00 +0000;Tue, 2 Jan 2024 19:30:00 +0000;Thu, 28 Dec 2023 16:00:00 +0000;Wed, 27 Dec 2023 16:00:00 +0000;Thu, 21 Dec 2023 19:30:00 +0000;Wed, 20 Dec 2023 19:30:00 +0000;Tue, 19 Dec 2023 19:30:00 +0000;Mon, 18 Dec 2023 19:30:00 +0000;Fri, 15 Dec 2023 19:30:00 +0000;Thu, 14 Dec 2023 19:26:18 +0000;Wed, 13 Dec 2023 19:55:01 +0000;Tue, 12 Dec 2023 19:54:36 +0000
+Fri, 16 Feb 2024 19:02:13 -0000;Fri, 16 Feb 2024 19:01:35 -0000;Thu, 15 Feb 2024 19:18:00 -0000;Thu, 15 Feb 2024 19:16:00 -0000;Wed, 14 Feb 2024 18:35:36 -0000;Wed, 14 Feb 2024 18:31:55 -0000;Tue, 13 Feb 2024 17:58:06 -0000;Tue, 13 Feb 2024 17:57:20 -0000;Mon, 12 Feb 2024 18:34:28 -0000;Mon, 12 Feb 2024 18:32:53 -0000;Sat, 10 Feb 2024 09:00:00 -0000;Fri, 09 Feb 2024 17:55:42 -0000;Thu, 08 Feb 2024 19:46:25 -0000;Thu, 08 Feb 2024 19:45:36 -0000;Wed, 07 Feb 2024 17:58:38 -0000;Wed, 07 Feb 2024 17:57:57 -0000;Tue, 06 Feb 2024 22:33:04 -0000;Tue, 06 Feb 2024 22:32:17 -0000;Mon, 05 Feb 2024 18:54:09 -0000;Mon, 05 Feb 2024 18:52:00 -0000;Sat, 03 Feb 2024 09:00:00 -0000;Fri, 02 Feb 2024 18:24:16 -0000;Fri, 02 Feb 2024 18:23:25 -0000;Thu, 01 Feb 2024 18:52:23 -0000;Thu, 01 Feb 2024 18:39:05 -0000;Wed, 31 Jan 2024 18:33:50 -0000;Wed, 31 Jan 2024 18:32:55 -0000;Tue, 30 Jan 2024 17:41:10 -0000;Mon, 29 Jan 2024 17:56:44 -0000;Mon, 29 Jan 2024 17:55:39 -0000;Fri, 26 Jan 2024 18:31:51 -0000;Fri, 26 Jan 2024 18:30:30 -0000;Thu, 25 Jan 2024 19:17:30 -0000;Thu, 25 Jan 2024 19:11:30 -0000;Wed, 24 Jan 2024 19:14:47 -0000;Wed, 24 Jan 2024 18:56:08 -0000;Tue, 23 Jan 2024 19:35:40 -0000;Tue, 23 Jan 2024 19:32:04 -0000;Mon, 22 Jan 2024 18:46:11 -0000;Mon, 22 Jan 2024 18:45:05 -0000;Sat, 20 Jan 2024 09:00:00 -0000;Fri, 19 Jan 2024 19:01:11 -0000;Fri, 19 Jan 2024 18:59:00 -0000;Thu, 18 Jan 2024 18:18:02 -0000;Thu, 18 Jan 2024 18:17:03 -0000;Wed, 17 Jan 2024 18:00:24 -0000;Wed, 17 Jan 2024 17:58:00 -0000;Tue, 16 Jan 2024 18:33:54 -0000;Tue, 16 Jan 2024 18:32:38 -0000;Mon, 15 Jan 2024 17:45:31 -0000
+Thu, 15 Feb 2024 11:00:00 +0000;Thu, 08 Feb 2024 11:00:00 +0000;Thu, 01 Feb 2024 11:00:00 +0000;Thu, 01 Feb 2024 11:00:00 +0000;Thu, 01 Feb 2024 11:00:00 +0000;Wed, 25 Jan 2023 12:00:00 +0000
+Thu, 15 Feb 2024 12:00:00 -0000;Thu, 08 Feb 2024 12:00:00 -0000;Thu, 01 Feb 2024 12:00:00 -0000;Thu, 25 Jan 2024 12:00:00 -0000;Thu, 18 Jan 2024 12:00:00 -0000;Thu, 11 Jan 2024 12:00:00 -0000;Thu, 21 Dec 2023 12:00:00 -0000;Thu, 14 Dec 2023 12:10:00 -0000;Thu, 07 Dec 2023 18:00:00 -0000;Tue, 05 Dec 2023 13:30:00 -0000
+Thu, 15 Feb 2024 18:19:20 +0000;Thu, 8 Feb 2024 18:38:40 +0000;Wed, 12 Oct 2022 00:00:00 +0000;Wed, 5 Oct 2022 00:00:00 +0000;Wed, 28 Sep 2022 00:00:00 +0000;Tue, 20 Sep 2022 23:56:13 +0000;Wed, 14 Sep 2022 00:00:00 +0000;Wed, 7 Sep 2022 00:00:00 +0000;Wed, 31 Aug 2022 00:00:00 +0000;Wed, 24 Aug 2022 00:00:00 +0000;Wed, 17 Aug 2022 00:00:00 +0000;Wed, 10 Aug 2022 00:00:00 +0000;Tue, 2 Aug 2022 23:39:17 +0000;Tue, 26 Jul 2022 23:00:00 +0000;Tue, 19 Jul 2022 23:55:00 +0000;Wed, 13 Jul 2022 00:00:00 +0000;Wed, 29 Jun 2022 00:00:00 +0000;Wed, 22 Jun 2022 00:00:00 +0000;Wed, 15 Jun 2022 00:00:00 +0000;Wed, 8 Jun 2022 00:00:00 +0000;Wed, 1 Jun 2022 00:15:00 +0000;Wed, 25 May 2022 12:03:43 +0000;Wed, 18 May 2022 00:00:00 +0000;Wed, 11 May 2022 00:00:00 +0000;Wed, 4 May 2022 00:00:00 +0000;Wed, 27 Apr 2022 00:00:00 +0000;Wed, 13 Apr 2022 00:00:00 +0000;Wed, 6 Apr 2022 00:00:00 +0000;Wed, 30 Mar 2022 00:00:00 +0000;Wed, 23 Mar 2022 00:00:00 +0000;Wed, 16 Mar 2022 00:00:00 +0000;Wed, 9 Mar 2022 00:00:00 +0000;Wed, 2 Mar 2022 01:37:21 +0000;Tue, 22 Feb 2022 23:57:28 +0000;Wed, 16 Feb 2022 00:45:00 +0000;Wed, 9 Feb 2022 03:37:27 +0000;Wed, 2 Feb 2022 00:45:00 +0000;Wed, 26 Jan 2022 02:40:00 +0000;Wed, 19 Jan 2022 01:06:08 +0000;Wed, 12 Jan 2022 03:04:18 +0000;Thu, 6 Jan 2022 00:45:00 +0000;Wed, 22 Dec 2021 00:45:00 +0000;Wed, 15 Dec 2021 00:45:00 +0000;Wed, 8 Dec 2021 00:45:00 +0000;Wed, 1 Dec 2021 01:30:00 +0000;Wed, 17 Nov 2021 00:45:00 +0000;Wed, 10 Nov 2021 03:18:22 +0000;Wed, 3 Nov 2021 02:58:23 +0000;Tue, 26 Oct 2021 23:45:00 +0000;Wed, 20 Oct 2021 01:00:00 +0000
+Tue, 13 Feb 2024 10:00:00 -0000;Thu, 08 Feb 2024 10:00:00 -0000;Tue, 06 Feb 2024 10:00:00 -0000;Tue, 30 Jan 2024 10:00:00 -0000;Thu, 25 Jan 2024 10:00:00 -0000;Tue, 23 Jan 2024 10:00:00 -0000;Mon, 22 Jan 2024 14:00:00 -0000;Thu, 18 Jan 2024 10:00:00 -0000;Tue, 16 Jan 2024 10:00:00 -0000;Thu, 11 Jan 2024 10:00:00 -0000;Tue, 09 Jan 2024 10:00:00 -0000;Tue, 02 Jan 2024 10:00:00 -0000;Tue, 19 Dec 2023 10:00:00 -0000;Fri, 15 Dec 2023 10:00:00 -0000;Thu, 14 Dec 2023 10:00:00 -0000;Tue, 12 Dec 2023 11:00:00 -0000;Tue, 05 Dec 2023 10:00:00 -0000;Thu, 30 Nov 2023 10:00:00 -0000;Tue, 28 Nov 2023 10:00:00 -0000;Thu, 16 Nov 2023 10:00:00 -0000;Tue, 14 Nov 2023 10:00:00 -0000;Tue, 07 Nov 2023 10:00:00 -0000;Tue, 31 Oct 2023 09:00:00 -0000;Fri, 27 Oct 2023 09:00:00 -0000;Thu, 19 Oct 2023 09:00:00 -0000;Tue, 17 Oct 2023 09:00:00 -0000;Thu, 12 Oct 2023 09:00:00 -0000;Tue, 10 Oct 2023 09:00:00 -0000;Thu, 05 Oct 2023 09:00:00 -0000;Tue, 03 Oct 2023 09:00:00 -0000;Thu, 28 Sep 2023 09:00:00 -0000;Tue, 26 Sep 2023 09:00:00 -0000;Thu, 21 Sep 2023 09:00:00 -0000;Tue, 19 Sep 2023 09:00:00 -0000;Thu, 14 Sep 2023 09:00:00 -0000;Tue, 12 Sep 2023 09:00:00 -0000;Thu, 07 Sep 2023 09:00:00 -0000;Tue, 05 Sep 2023 09:00:00 -0000;Thu, 31 Aug 2023 09:00:00 -0000;Tue, 29 Aug 2023 10:00:00 -0000;Thu, 24 Aug 2023 09:00:00 -0000;Tue, 22 Aug 2023 12:51:00 -0000;Mon, 21 Aug 2023 09:00:00 -0000;Thu, 17 Aug 2023 09:00:00 -0000;Tue, 15 Aug 2023 09:00:00 -0000;Tue, 08 Aug 2023 09:00:00 -0000;Thu, 03 Aug 2023 09:00:00 -0000;Tue, 01 Aug 2023 09:00:00 -0000;Tue, 25 Jul 2023 12:50:00 -0000;Thu, 20 Jul 2023 09:00:00 -0000
+Fri, 16 Feb 2024 21:15:00 -0000;Thu, 15 Feb 2024 20:38:00 -0000;Wed, 14 Feb 2024 21:04:00 -0000;Tue, 13 Feb 2024 21:20:00 -0000;Mon, 12 Feb 2024 21:00:00 -0000;Fri, 09 Feb 2024 21:13:00 -0000;Thu, 08 Feb 2024 21:33:00 -0000;Wed, 07 Feb 2024 20:52:00 -0000;Tue, 06 Feb 2024 21:40:00 -0000;Mon, 05 Feb 2024 21:18:00 -0000;Fri, 02 Feb 2024 20:52:00 -0000;Thu, 01 Feb 2024 21:30:00 -0000;Wed, 31 Jan 2024 21:00:00 -0000;Tue, 30 Jan 2024 20:26:00 -0000;Mon, 29 Jan 2024 21:35:00 -0000;Fri, 26 Jan 2024 21:29:00 -0000;Thu, 25 Jan 2024 21:12:00 -0000;Wed, 24 Jan 2024 21:03:00 -0000;Tue, 23 Jan 2024 22:01:00 -0000;Mon, 22 Jan 2024 21:35:00 -0000;Fri, 19 Jan 2024 21:53:00 -0000;Thu, 18 Jan 2024 21:00:00 -0000;Wed, 17 Jan 2024 21:24:00 -0000;Tue, 16 Jan 2024 21:25:00 -0000;Sun, 14 Jan 2024 11:00:00 -0000;Fri, 12 Jan 2024 21:06:00 -0000;Thu, 11 Jan 2024 21:36:00 -0000;Wed, 10 Jan 2024 21:37:00 -0000;Tue, 09 Jan 2024 21:55:00 -0000;Mon, 08 Jan 2024 21:27:00 -0000;Sun, 07 Jan 2024 11:00:00 -0000;Fri, 05 Jan 2024 21:02:00 -0000;Thu, 04 Jan 2024 21:34:00 -0000;Wed, 03 Jan 2024 21:00:00 -0000;Tue, 02 Jan 2024 21:30:00 -0000;Tue, 26 Dec 2023 21:00:00 -0000;Fri, 22 Dec 2023 19:15:00 -0000;Thu, 21 Dec 2023 21:00:00 -0000;Wed, 20 Dec 2023 21:00:00 -0000;Tue, 19 Dec 2023 21:00:00 -0000;Mon, 18 Dec 2023 21:00:00 -0000;Fri, 15 Dec 2023 21:30:00 -0000;Thu, 14 Dec 2023 21:16:00 -0000;Wed, 13 Dec 2023 21:18:00 -0000;Tue, 12 Dec 2023 20:35:00 -0000;Mon, 11 Dec 2023 21:38:00 -0000;Sun, 10 Dec 2023 11:00:00 -0000;Fri, 08 Dec 2023 21:28:00 -0000;Thu, 07 Dec 2023 21:14:00 -0000;Wed, 06 Dec 2023 21:55:00 -0000
+Fri, 16 Feb 2024 11:00:00 -0000;Tue, 13 Feb 2024 11:00:00 -0000;Fri, 09 Feb 2024 11:00:00 -0000;Tue, 06 Feb 2024 11:00:00 -0000;Fri, 02 Feb 2024 11:00:00 -0000;Tue, 30 Jan 2024 11:00:00 -0000;Fri, 26 Jan 2024 11:00:00 -0000;Tue, 23 Jan 2024 11:00:00 -0000;Fri, 19 Jan 2024 11:00:00 -0000;Tue, 16 Jan 2024 11:00:00 -0000;Fri, 12 Jan 2024 11:00:00 -0000;Mon, 08 Jan 2024 19:28:31 -0000;Fri, 05 Jan 2024 11:00:00 -0000;Fri, 29 Dec 2023 11:00:00 -0000;Fri, 22 Dec 2023 11:00:00 -0000;Tue, 19 Dec 2023 11:00:00 -0000;Fri, 15 Dec 2023 11:00:00 -0000;Tue, 12 Dec 2023 11:00:00 -0000;Fri, 08 Dec 2023 11:00:00 -0000;Tue, 05 Dec 2023 11:00:00 -0000;Fri, 01 Dec 2023 11:00:00 -0000;Tue, 28 Nov 2023 11:00:00 -0000;Fri, 24 Nov 2023 11:00:00 -0000;Tue, 21 Nov 2023 11:00:00 -0000;Tue, 21 Nov 2023 02:07:00 -0000;Sat, 18 Nov 2023 08:00:00 -0000;Fri, 17 Nov 2023 11:00:00 -0000;Tue, 14 Nov 2023 11:00:00 -0000;Fri, 10 Nov 2023 11:00:00 -0000;Tue, 07 Nov 2023 11:00:00 -0000;Fri, 03 Nov 2023 10:00:00 -0000;Tue, 31 Oct 2023 10:00:00 -0000;Fri, 27 Oct 2023 10:00:00 -0000;Wed, 25 Oct 2023 10:00:00 -0000;Tue, 24 Oct 2023 10:00:00 -0000;Fri, 20 Oct 2023 10:00:00 -0000;Tue, 17 Oct 2023 10:00:00 -0000;Fri, 13 Oct 2023 10:00:00 -0000;Tue, 10 Oct 2023 10:00:00 -0000;Fri, 06 Oct 2023 10:00:00 -0000;Wed, 04 Oct 2023 10:00:00 -0000;Tue, 03 Oct 2023 10:00:00 -0000;Sat, 30 Sep 2023 10:00:00 -0000;Fri, 29 Sep 2023 10:00:00 -0000;Tue, 26 Sep 2023 10:00:00 -0000;Fri, 22 Sep 2023 10:00:00 -0000;Tue, 19 Sep 2023 10:00:00 -0000;Fri, 15 Sep 2023 10:00:00 -0000;Tue, 12 Sep 2023 10:00:00 -0000;Fri, 08 Sep 2023 10:00:00 -0000
+Fri, 16 Feb 2024 05:26:21 +0000;Fri, 09 Feb 2024 07:49:54 +0000;Fri, 02 Feb 2024 07:38:29 +0000;Fri, 26 Jan 2024 10:44:09 +0000;Fri, 19 Jan 2024 16:02:16 +0000;Fri, 12 Jan 2024 14:00:00 +0000;Fri, 05 Jan 2024 14:00:00 +0000;Fri, 22 Dec 2023 17:42:06 +0000;Fri, 15 Dec 2023 13:00:00 +0000;Fri, 08 Dec 2023 16:33:03 +0000;Sat, 02 Dec 2023 01:45:01 +0000;Fri, 24 Nov 2023 11:00:00 +0000;Fri, 17 Nov 2023 20:11:14 +0000;Fri, 10 Nov 2023 21:34:29 +0000;Fri, 03 Nov 2023 12:00:00 +0000;Fri, 27 Oct 2023 13:00:00 +0000;Fri, 20 Oct 2023 17:13:55 +0000;Fri, 13 Oct 2023 12:00:00 +0000;Fri, 06 Oct 2023 20:22:51 +0000;Fri, 29 Sep 2023 13:00:00 +0000;Fri, 22 Sep 2023 21:09:10 +0000;Fri, 15 Sep 2023 20:29:16 +0000;Fri, 08 Sep 2023 16:00:00 +0000;Sat, 02 Sep 2023 00:42:53 +0000;Fri, 25 Aug 2023 20:18:27 +0000;Fri, 18 Aug 2023 16:49:36 +0000;Fri, 11 Aug 2023 21:18:57 +0000;Fri, 04 Aug 2023 09:16:39 +0000;Fri, 28 Jul 2023 17:36:08 +0000;Fri, 21 Jul 2023 23:07:38 +0000;Fri, 14 Jul 2023 07:46:04 +0000;Fri, 07 Jul 2023 07:34:53 +0000;Sat, 24 Jun 2023 07:46:08 +0000;Sat, 10 Jun 2023 04:11:18 +0000;Tue, 30 May 2023 19:06:17 +0000;Wed, 10 May 2023 08:17:37 +0000
+Fri, 16 Feb 2024 21:22:44 +0000;Thu, 15 Feb 2024 20:55:38 +0000;Wed, 14 Feb 2024 20:55:20 +0000;Tue, 13 Feb 2024 20:20:17 +0000;Mon, 12 Feb 2024 22:18:41 +0000;Fri, 09 Feb 2024 22:08:37 +0000;Fri, 09 Feb 2024 00:54:41 +0000;Thu, 08 Feb 2024 21:15:41 +0000;Wed, 07 Feb 2024 21:53:10 +0000;Tue, 06 Feb 2024 22:03:54 +0000;Mon, 05 Feb 2024 21:29:55 +0000;Fri, 02 Feb 2024 21:04:31 +0000;Thu, 01 Feb 2024 21:41:30 +0000;Wed, 31 Jan 2024 20:36:41 +0000;Tue, 30 Jan 2024 21:08:51 +0000;Mon, 29 Jan 2024 21:26:16 +0000;Fri, 26 Jan 2024 22:43:46 +0000;Thu, 25 Jan 2024 21:30:05 +0000;Wed, 24 Jan 2024 20:55:26 +0000;Wed, 24 Jan 2024 05:48:11 +0000;Mon, 22 Jan 2024 21:11:20 +0000;Fri, 19 Jan 2024 21:51:04 +0000;Thu, 18 Jan 2024 21:18:06 +0000;Wed, 17 Jan 2024 21:24:16 +0000;Tue, 16 Jan 2024 20:31:14 +0000;Tue, 16 Jan 2024 06:28:18 +0000;Fri, 12 Jan 2024 22:01:54 +0000;Thu, 11 Jan 2024 21:36:28 +0000;Wed, 10 Jan 2024 21:40:11 +0000;Tue, 09 Jan 2024 21:18:43 +0000;Mon, 08 Jan 2024 20:53:56 +0000;Fri, 05 Jan 2024 23:05:25 +0000;Thu, 04 Jan 2024 22:13:48 +0000;Wed, 03 Jan 2024 21:15:53 +0000;Tue, 02 Jan 2024 20:11:11 +0000;Mon, 01 Jan 2024 08:00:00 +0000;Fri, 29 Dec 2023 20:58:22 +0000;Thu, 28 Dec 2023 20:23:53 +0000;Wed, 27 Dec 2023 20:26:08 +0000;Tue, 26 Dec 2023 20:08:19 +0000;Mon, 25 Dec 2023 08:00:00 +0000;Fri, 22 Dec 2023 18:22:51 +0000;Thu, 21 Dec 2023 20:46:49 +0000;Wed, 20 Dec 2023 20:42:14 +0000;Tue, 19 Dec 2023 20:14:14 +0000;Mon, 18 Dec 2023 21:39:49 +0000;Sun, 17 Dec 2023 08:00:00 +0000;Fri, 15 Dec 2023 20:31:57 +0000;Thu, 14 Dec 2023 21:50:02 +0000;Thu, 14 Dec 2023 01:21:13 +0000
+Fri, 16 Feb 2024 12:25:57 -0000;Thu, 15 Feb 2024 23:08:12 -0000;Wed, 14 Feb 2024 11:45:36 -0000;Wed, 14 Feb 2024 11:43:44 -0000;Tue, 13 Feb 2024 16:05:34 -0000;Tue, 13 Feb 2024 03:51:50 -0000;Tue, 13 Feb 2024 03:36:45 -0000;Fri, 09 Feb 2024 13:39:25 -0000;Thu, 08 Feb 2024 21:01:00 -0000;Wed, 07 Feb 2024 23:23:38 -0000;Wed, 07 Feb 2024 23:04:26 -0000;Tue, 06 Feb 2024 20:46:08 -0000;Tue, 06 Feb 2024 13:34:15 -0000;Mon, 05 Feb 2024 00:30:54 -0000;Fri, 02 Feb 2024 13:28:22 -0000;Thu, 01 Feb 2024 23:25:39 -0000;Thu, 01 Feb 2024 21:56:05 -0000;Thu, 01 Feb 2024 00:03:52 -0000;Wed, 31 Jan 2024 22:43:16 -0000;Tue, 30 Jan 2024 13:41:46 -0000;Mon, 29 Jan 2024 23:37:40 -0000;Mon, 29 Jan 2024 22:43:59 -0000;Fri, 26 Jan 2024 15:35:48 -0000;Thu, 25 Jan 2024 22:08:20 -0000;Thu, 25 Jan 2024 00:25:45 -0000;Wed, 24 Jan 2024 22:37:01 -0000;Tue, 23 Jan 2024 22:10:35 -0000;Tue, 23 Jan 2024 12:30:44 -0000;Mon, 22 Jan 2024 22:02:26 -0000;Fri, 19 Jan 2024 16:50:03 -0000;Thu, 18 Jan 2024 20:27:41 -0000;Wed, 17 Jan 2024 13:10:15 -0000;Tue, 16 Jan 2024 12:59:12 -0000;Mon, 15 Jan 2024 22:13:31 -0000;Sat, 13 Jan 2024 08:21:40 -0000;Fri, 12 Jan 2024 17:58:55 -0000;Thu, 11 Jan 2024 21:27:22 -0000;Wed, 10 Jan 2024 18:24:28 -0000;Wed, 10 Jan 2024 16:38:43 -0000;Tue, 09 Jan 2024 20:00:00 -0000;Tue, 09 Jan 2024 15:41:43 -0000;Tue, 09 Jan 2024 03:50:50 -0000;Mon, 08 Jan 2024 22:18:56 -0000;Sat, 06 Jan 2024 16:41:09 -0000;Sat, 06 Jan 2024 00:20:54 -0000;Fri, 05 Jan 2024 23:26:39 -0000;Fri, 05 Jan 2024 14:00:00 -0000;Thu, 04 Jan 2024 22:26:55 -0000;Thu, 04 Jan 2024 00:07:34 -0000;Wed, 03 Jan 2024 22:03:37 -0000
+Sat, 17 Feb 2024 08:00:00 +0000;Wed, 14 Feb 2024 08:00:00 +0000;Sat, 10 Feb 2024 08:00:00 +0000;Wed, 07 Feb 2024 08:00:00 +0000;Sat, 03 Feb 2024 08:00:00 +0000;Wed, 31 Jan 2024 08:00:00 +0000;Sat, 27 Jan 2024 08:00:00 +0000;Wed, 24 Jan 2024 08:00:00 +0000;Sat, 20 Jan 2024 08:00:00 +0000;Wed, 17 Jan 2024 08:00:00 +0000;Sat, 13 Jan 2024 08:00:00 +0000;Wed, 10 Jan 2024 08:00:00 +0000;Sat, 06 Jan 2024 08:00:00 +0000;Sat, 30 Dec 2023 08:00:00 +0000;Sat, 23 Dec 2023 08:00:00 +0000;Wed, 20 Dec 2023 08:00:00 +0000;Sat, 16 Dec 2023 09:30:00 +0000;Wed, 13 Dec 2023 08:00:00 +0000;Sat, 09 Dec 2023 08:00:00 +0000;Wed, 06 Dec 2023 08:00:00 +0000;Sat, 02 Dec 2023 08:00:00 +0000;Wed, 29 Nov 2023 08:00:00 +0000;Sat, 25 Nov 2023 08:00:00 +0000;Wed, 22 Nov 2023 08:00:00 +0000;Wed, 15 Nov 2023 08:00:00 +0000;Sat, 11 Nov 2023 08:00:00 +0000;Wed, 08 Nov 2023 08:00:00 +0000;Sat, 04 Nov 2023 07:00:00 +0000;Wed, 01 Nov 2023 07:00:00 +0000;Sat, 28 Oct 2023 07:00:00 +0000;Wed, 25 Oct 2023 07:00:00 +0000;Sat, 21 Oct 2023 07:30:00 +0000;Wed, 18 Oct 2023 07:00:00 +0000;Sat, 14 Oct 2023 08:00:00 +0000;Sat, 07 Oct 2023 07:00:00 +0000;Wed, 04 Oct 2023 07:00:00 +0000;Sat, 30 Sep 2023 07:00:00 +0000;Wed, 27 Sep 2023 07:00:00 +0000;Sat, 23 Sep 2023 07:00:00 +0000;Wed, 20 Sep 2023 07:00:00 +0000;Sat, 16 Sep 2023 07:00:00 +0000;Wed, 13 Sep 2023 07:00:00 +0000;Sat, 09 Sep 2023 07:00:00 +0000;Wed, 30 Aug 2023 07:00:00 +0000;Sat, 26 Aug 2023 07:00:00 +0000;Wed, 23 Aug 2023 07:00:00 +0000;Sat, 19 Aug 2023 07:00:00 +0000;Wed, 16 Aug 2023 07:00:00 +0000;Sat, 12 Aug 2023 05:30:00 +0000;Wed, 09 Aug 2023 07:00:00 +0000
+Tue, 13 Feb 2024 08:00:00 +0000;Mon, 05 Feb 2024 19:58:36 +0000;Tue, 30 Jan 2024 08:21:00 +0000
diff --git a/core/src/test/resources/release_dates.sh b/core/src/test/resources/release_dates.sh
new file mode 100755
index 000000000..e09373a42
--- /dev/null
+++ b/core/src/test/resources/release_dates.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+ids=$(curl --silent "https://itunes.apple.com/US/rss/toppodcasts/limit=150/explicit=true/json" | jq --raw-output ".feed.entry[].id.attributes.[\"im:id\"]")
+
+echo "$ids" | while IFS= read -r id;
+do
+ url=$(curl --silent "https://itunes.apple.com/lookup?id=$id" | jq --raw-output ".results[0].feedUrl")
+ dates=$(curl --silent "$url" | yq --input-format xml ".rss.channel.item[].pubDate")
+ echo -en "$dates" | head -n 50 | paste -sd ";"
+done
diff --git a/event/src/main/java/de/danoeh/antennapod/event/settings/SpeedPresetChangedEvent.java b/event/src/main/java/de/danoeh/antennapod/event/settings/SpeedPresetChangedEvent.java
index 6ca8a1290..bc7c46785 100644
--- a/event/src/main/java/de/danoeh/antennapod/event/settings/SpeedPresetChangedEvent.java
+++ b/event/src/main/java/de/danoeh/antennapod/event/settings/SpeedPresetChangedEvent.java
@@ -1,18 +1,26 @@
package de.danoeh.antennapod.event.settings;
+import de.danoeh.antennapod.model.feed.FeedPreferences;
+
public class SpeedPresetChangedEvent {
private final float speed;
+ private final FeedPreferences.SkipSilence skipSilence;
private final long feedId;
- public SpeedPresetChangedEvent(float speed, long feedId) {
+ public SpeedPresetChangedEvent(float speed, long feedId, FeedPreferences.SkipSilence skipSilence) {
this.speed = speed;
this.feedId = feedId;
+ this.skipSilence = skipSilence;
}
public float getSpeed() {
return speed;
}
+ public FeedPreferences.SkipSilence getSkipSilence() {
+ return skipSilence;
+ }
+
public long getFeedId() {
return feedId;
}
diff --git a/gradle.properties b/gradle.properties
index e57f3d564..15553a59c 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,4 +1,4 @@
android.useAndroidX=true
-android.enableJetifier=true
-android.jetifier.ignorelist=bcprov-jdk15on
org.gradle.jvmargs=-Xmx4096m
+android.defaults.buildfeatures.buildconfig=true
+android.nonTransitiveRClass=false
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index c1962a79e..d64cd4917 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 37aef8d3f..a80b22ce5 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index aeb74cbb4..1aa94a426 100755
--- a/gradlew
+++ b/gradlew
@@ -83,7 +83,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -130,10 +131,13 @@ location of your Java installation."
fi
else
JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
@@ -141,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
+ # shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@@ -149,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
+ # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -198,11 +202,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-# Collect all arguments for the java command;
-# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
-# shell script including quotes and variable substitutions, so put them in
-# double quotes to make sure that they get re-expanded; and
-# * put everything else in single quotes, so that it's not re-expanded.
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
diff --git a/gradlew.bat b/gradlew.bat
index 6689b85be..7101f8e46 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
diff --git a/model/src/main/java/de/danoeh/antennapod/model/download/DownloadResult.java b/model/src/main/java/de/danoeh/antennapod/model/download/DownloadResult.java
index 66901cf65..8654db87e 100644
--- a/model/src/main/java/de/danoeh/antennapod/model/download/DownloadResult.java
+++ b/model/src/main/java/de/danoeh/antennapod/model/download/DownloadResult.java
@@ -4,8 +4,6 @@ import androidx.annotation.NonNull;
import java.util.Date;
-import de.danoeh.antennapod.model.feed.FeedFile;
-
/**
* Contains status attributes for one download
*/
@@ -42,18 +40,13 @@ public class DownloadResult {
private boolean successful;
private final Date completionDate;
- /**
- * Constructor for creating new completed downloads.
- */
- public DownloadResult(@NonNull FeedFile feedfile, String title, DownloadError reason, boolean successful,
- String reasonDetailed) {
- this(0, title, feedfile.getId(), feedfile.getTypeAsInt(), successful, reason, new Date(),
- reasonDetailed);
+ public DownloadResult(String title, long feedfileId, int feedfileType, boolean successful,
+ DownloadError reason, String reasonDetailed) {
+ this(0, title, feedfileId, feedfileType, successful, reason, new Date(), reasonDetailed);
}
public DownloadResult(long id, String title, long feedfileId, int feedfileType, boolean successful,
- DownloadError reason, Date completionDate,
- String reasonDetailed) {
+ DownloadError reason, Date completionDate, String reasonDetailed) {
this.id = id;
this.title = title;
this.feedfileId = feedfileId;
diff --git a/model/src/main/java/de/danoeh/antennapod/model/feed/Chapter.java b/model/src/main/java/de/danoeh/antennapod/model/feed/Chapter.java
index e55364dd9..3f4116f9c 100644
--- a/model/src/main/java/de/danoeh/antennapod/model/feed/Chapter.java
+++ b/model/src/main/java/de/danoeh/antennapod/model/feed/Chapter.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.model.feed;
-public class Chapter extends FeedComponent {
+public class Chapter {
+ private long id;
/** Defines starting point in milliseconds. */
private long start;
private String title;
@@ -62,12 +63,15 @@ public class Chapter extends FeedComponent {
}
@Override
- public String getHumanReadableIdentifier() {
- return title;
- }
-
- @Override
public String toString() {
return "ID3Chapter [title=" + getTitle() + ", start=" + getStart() + ", url=" + getLink() + "]";
}
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
}
diff --git a/model/src/main/java/de/danoeh/antennapod/model/feed/Feed.java b/model/src/main/java/de/danoeh/antennapod/model/feed/Feed.java
index 94a4776a5..0ea7dd1b7 100644
--- a/model/src/main/java/de/danoeh/antennapod/model/feed/Feed.java
+++ b/model/src/main/java/de/danoeh/antennapod/model/feed/Feed.java
@@ -3,6 +3,7 @@ package de.danoeh.antennapod.model.feed;
import android.text.TextUtils;
import androidx.annotation.Nullable;
+import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Date;
@@ -13,7 +14,7 @@ import java.util.List;
*
* @author daniel
*/
-public class Feed extends FeedFile {
+public class Feed {
public static final int FEEDFILETYPE_FEED = 0;
public static final String TYPE_RSS2 = "rss";
@@ -21,6 +22,10 @@ public class Feed extends FeedFile {
public static final String PREFIX_LOCAL_FOLDER = "antennapod_local:";
public static final String PREFIX_GENERATIVE_COVER = "antennapod_generative_cover:";
+ private long id;
+ private String localFileUrl;
+ private String downloadUrl;
+ private boolean downloaded;
/**
* title as defined by the feed.
*/
@@ -51,7 +56,7 @@ public class Feed extends FeedFile {
/**
* String that identifies the last update (adopted from Last-Modified or ETag header).
*/
- private String lastUpdate;
+ private String lastModified;
private ArrayList<FeedFunding> fundingList;
/**
@@ -102,16 +107,18 @@ public class Feed extends FeedFile {
/**
* This constructor is used for restoring a feed from the database.
*/
- public Feed(long id, String lastUpdate, String title, String customTitle, String link,
+ public Feed(long id, String lastModified, String title, String customTitle, String link,
String description, String paymentLinks, String author, String language,
String type, String feedIdentifier, String imageUrl, String fileUrl,
String downloadUrl, boolean downloaded, boolean paged, String nextPageLink,
String filter, @Nullable SortOrder sortOrder, boolean lastUpdateFailed) {
- super(fileUrl, downloadUrl, downloaded);
+ this.localFileUrl = fileUrl;
+ this.downloadUrl = downloadUrl;
+ this.downloaded = downloaded;
this.id = id;
this.feedTitle = title;
this.customTitle = customTitle;
- this.lastUpdate = lastUpdate;
+ this.lastModified = lastModified;
this.link = link;
this.description = description;
this.fundingList = FeedFunding.extractPaymentLinks(paymentLinks);
@@ -135,11 +142,11 @@ public class Feed extends FeedFile {
/**
* This constructor is used for test purposes.
*/
- public Feed(long id, String lastUpdate, String title, String link, String description, String paymentLink,
+ public Feed(long id, String lastModified, String title, String link, String description, String paymentLink,
String author, String language, String type, String feedIdentifier, String imageUrl, String fileUrl,
String downloadUrl, boolean downloaded) {
- this(id, lastUpdate, title, null, link, description, paymentLink, author, language, type, feedIdentifier, imageUrl,
- fileUrl, downloadUrl, downloaded, false, null, null, null, false);
+ this(id, lastModified, title, null, link, description, paymentLink, author, language, type, feedIdentifier,
+ imageUrl, fileUrl, downloadUrl, downloaded, false, null, null, null, false);
}
/**
@@ -153,17 +160,19 @@ public class Feed extends FeedFile {
* This constructor is used for requesting a feed download (it must not be used for anything else!). It should NOT be
* used if the title of the feed is already known.
*/
- public Feed(String url, String lastUpdate) {
- super(null, url, false);
- this.lastUpdate = lastUpdate;
+ public Feed(String url, String lastModified) {
+ this.localFileUrl = null;
+ this.downloadUrl = url;
+ this.downloaded = false;
+ this.lastModified = lastModified;
}
/**
* This constructor is used for requesting a feed download (it must not be used for anything else!). It should be
* used if the title of the feed is already known.
*/
- public Feed(String url, String lastUpdate, String title) {
- this(url, lastUpdate);
+ public Feed(String url, String lastModified, String title) {
+ this(url, lastModified);
this.feedTitle = title;
}
@@ -171,8 +180,8 @@ public class Feed extends FeedFile {
* This constructor is used for requesting a feed download (it must not be used for anything else!). It should be
* used if the title of the feed is already known.
*/
- public Feed(String url, String lastUpdate, String title, String username, String password) {
- this(url, lastUpdate, title);
+ public Feed(String url, String lastModified, String title, String username, String password) {
+ this(url, lastModified, title);
preferences = new FeedPreferences(0, true, FeedPreferences.AutoDeleteAction.GLOBAL, VolumeAdaptionSetting.OFF,
FeedPreferences.NewEpisodesAction.GLOBAL, username, password);
}
@@ -194,8 +203,8 @@ public class Feed extends FeedFile {
public String getIdentifyingValue() {
if (feedIdentifier != null && !feedIdentifier.isEmpty()) {
return feedIdentifier;
- } else if (download_url != null && !download_url.isEmpty()) {
- return download_url;
+ } else if (downloadUrl != null && !downloadUrl.isEmpty()) {
+ return downloadUrl;
} else if (feedTitle != null && !feedTitle.isEmpty()) {
return feedTitle;
} else {
@@ -203,14 +212,13 @@ public class Feed extends FeedFile {
}
}
- @Override
public String getHumanReadableIdentifier() {
if (!TextUtils.isEmpty(customTitle)) {
return customTitle;
} else if (!TextUtils.isEmpty(feedTitle)) {
return feedTitle;
} else {
- return download_url;
+ return downloadUrl;
}
}
@@ -249,8 +257,15 @@ public class Feed extends FeedFile {
}
}
+ /**
+ * Compare's this FeedFile's attribute values with another FeedFile's
+ * attribute values. This method will only compare attributes which were
+ * read from the feed.
+ *
+ * @return true if attribute values are different, false otherwise
+ */
public boolean compareWithOther(Feed other) {
- if (super.compareWithOther(other)) {
+ if (!StringUtils.equals(downloadUrl, other.downloadUrl)) {
return true;
}
if (other.imageUrl != null) {
@@ -313,11 +328,6 @@ public class Feed extends FeedFile {
return mostRecentItem;
}
- @Override
- public int getTypeAsInt() {
- return FEEDFILETYPE_FEED;
- }
-
public String getTitle() {
return !TextUtils.isEmpty(customTitle) ? customTitle : feedTitle;
}
@@ -375,12 +385,12 @@ public class Feed extends FeedFile {
this.items = list;
}
- public String getLastUpdate() {
- return lastUpdate;
+ public String getLastModified() {
+ return lastModified;
}
- public void setLastUpdate(String lastModified) {
- this.lastUpdate = lastModified;
+ public void setLastModified(String lastModified) {
+ this.lastModified = lastModified;
}
public String getFeedIdentifier() {
@@ -434,14 +444,44 @@ public class Feed extends FeedFile {
return preferences;
}
- @Override
public void setId(long id) {
- super.setId(id);
+ this.id = id;
if (preferences != null) {
preferences.setFeedID(id);
}
}
+ public long getId() {
+ return id;
+ }
+
+ public String getFile_url() {
+ return localFileUrl;
+ }
+
+ public void setFile_url(String fileUrl) {
+ this.localFileUrl = fileUrl;
+ if (fileUrl == null) {
+ downloaded = false;
+ }
+ }
+
+ public String getDownload_url() {
+ return downloadUrl;
+ }
+
+ public void setDownload_url(String downloadUrl) {
+ this.downloadUrl = downloadUrl;
+ }
+
+ public boolean isDownloaded() {
+ return downloaded;
+ }
+
+ public void setDownloaded(boolean downloaded) {
+ this.downloaded = downloaded;
+ }
+
public int getPageNr() {
return pageNr;
}
@@ -499,6 +539,6 @@ public class Feed extends FeedFile {
}
public boolean isLocalFeed() {
- return download_url.startsWith(PREFIX_LOCAL_FOLDER);
+ return downloadUrl.startsWith(PREFIX_LOCAL_FOLDER);
}
}
diff --git a/model/src/main/java/de/danoeh/antennapod/model/feed/FeedComponent.java b/model/src/main/java/de/danoeh/antennapod/model/feed/FeedComponent.java
deleted file mode 100644
index fa0ace3dc..000000000
--- a/model/src/main/java/de/danoeh/antennapod/model/feed/FeedComponent.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package de.danoeh.antennapod.model.feed;
-
-/**
- * Represents every possible component of a feed
- *
- * @author daniel
- */
-public abstract class FeedComponent {
-
- long id;
-
- FeedComponent() {
- super();
- }
-
- public long getId() {
- return id;
- }
-
- public void setId(long id) {
- this.id = id;
- }
-
- /**
- * Update this FeedComponent's attributes with the attributes from another
- * FeedComponent. This method should only update attributes which where read from
- * the feed.
- */
- void updateFromOther(FeedComponent other) {
- }
-
- /**
- * Compare's this FeedComponent's attribute values with another FeedComponent's
- * attribute values. This method will only compare attributes which were
- * read from the feed.
- *
- * @return true if attribute values are different, false otherwise
- */
- boolean compareWithOther(FeedComponent other) {
- return false;
- }
-
-
- /**
- * Should return a non-null, human-readable String so that the item can be
- * identified by the user. Can be title, download-url, etc.
- */
- public abstract String getHumanReadableIdentifier();
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof FeedComponent)) return false;
-
- FeedComponent that = (FeedComponent) o;
-
- return id == that.id;
-
- }
-
- @Override
- public int hashCode() {
- return (int) (id ^ (id >>> 32));
- }
-}
diff --git a/model/src/main/java/de/danoeh/antennapod/model/feed/FeedFile.java b/model/src/main/java/de/danoeh/antennapod/model/feed/FeedFile.java
deleted file mode 100644
index c04fa0bb9..000000000
--- a/model/src/main/java/de/danoeh/antennapod/model/feed/FeedFile.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package de.danoeh.antennapod.model.feed;
-
-import android.text.TextUtils;
-
-import java.io.File;
-
-/**
- * Represents a component of a Feed that has to be downloaded
- */
-public abstract class FeedFile extends FeedComponent {
-
- String file_url;
- protected String download_url;
- boolean downloaded;
-
- /**
- * Creates a new FeedFile object.
- *
- * @param file_url The location of the FeedFile. If this is null, the downloaded-attribute
- * will automatically be set to false.
- * @param download_url The location where the FeedFile can be downloaded.
- * @param downloaded true if the FeedFile has been downloaded, false otherwise. This parameter
- * will automatically be interpreted as false if the file_url is null.
- */
- public FeedFile(String file_url, String download_url, boolean downloaded) {
- super();
- this.file_url = file_url;
- this.download_url = download_url;
- this.downloaded = (file_url != null) && downloaded;
- }
-
- public FeedFile() {
- this(null, null, false);
- }
-
- public abstract int getTypeAsInt();
-
- /**
- * Update this FeedFile's attributes with the attributes from another
- * FeedFile. This method should only update attributes which where read from
- * the feed.
- */
- void updateFromOther(FeedFile other) {
- super.updateFromOther(other);
- this.download_url = other.download_url;
- }
-
- /**
- * Compare's this FeedFile's attribute values with another FeedFile's
- * attribute values. This method will only compare attributes which were
- * read from the feed.
- *
- * @return true if attribute values are different, false otherwise
- */
- boolean compareWithOther(FeedFile other) {
- if (super.compareWithOther(other)) {
- return true;
- }
- if (!TextUtils.equals(download_url, other.download_url)) {
- return true;
- }
- return false;
- }
-
- /**
- * Returns true if the file exists at file_url.
- */
- public boolean fileExists() {
- if (file_url == null) {
- return false;
- } else {
- File f = new File(file_url);
- return f.exists();
- }
- }
-
- public String getFile_url() {
- return file_url;
- }
-
- /**
- * Changes the file_url of this FeedFile. Setting this value to
- * null will also set the downloaded-attribute to false.
- */
- public void setFile_url(String file_url) {
- this.file_url = file_url;
- if (file_url == null) {
- downloaded = false;
- }
- }
-
- public String getDownload_url() {
- return download_url;
- }
-
- public void setDownload_url(String download_url) {
- this.download_url = download_url;
- }
-
- public boolean isDownloaded() {
- return downloaded;
- }
-
- public void setDownloaded(boolean downloaded) {
- this.downloaded = downloaded;
- }
-}
diff --git a/model/src/main/java/de/danoeh/antennapod/model/feed/FeedItem.java b/model/src/main/java/de/danoeh/antennapod/model/feed/FeedItem.java
index be0760bdb..25ea9330c 100644
--- a/model/src/main/java/de/danoeh/antennapod/model/feed/FeedItem.java
+++ b/model/src/main/java/de/danoeh/antennapod/model/feed/FeedItem.java
@@ -17,13 +17,14 @@ import java.util.Set;
*
* @author daniel
*/
-public class FeedItem extends FeedComponent implements Serializable {
+public class FeedItem implements Serializable {
/** tag that indicates this item is in the queue */
public static final String TAG_QUEUE = "Queue";
/** tag that indicates this item is in favorites */
public static final String TAG_FAVORITE = "Favorite";
+ private long id;
/**
* The id/guid that can be found in the rss/atom feed. Might not be set.
*/
@@ -125,7 +126,6 @@ public class FeedItem extends FeedComponent implements Serializable {
}
public void updateFromOther(FeedItem other) {
- super.updateFromOther(other);
if (other.imageUrl != null) {
this.imageUrl = other.imageUrl;
}
@@ -163,6 +163,14 @@ public class FeedItem extends FeedComponent implements Serializable {
}
}
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
/**
* Returns the value that uniquely identifies this FeedItem. If the
* itemIdentifier attribute is not null, it will be returned. Else it will
@@ -325,10 +333,6 @@ public class FeedItem extends FeedComponent implements Serializable {
}
}
- public enum State {
- UNREAD, IN_PROGRESS, READ, PLAYING
- }
-
public long getFeedId() {
return feedId;
}
@@ -350,11 +354,6 @@ public class FeedItem extends FeedComponent implements Serializable {
this.imageUrl = imageUrl;
}
- @Override
- public String getHumanReadableIdentifier() {
- return title;
- }
-
public boolean hasChapters() {
return hasChapters;
}
diff --git a/model/src/main/java/de/danoeh/antennapod/model/feed/FeedMedia.java b/model/src/main/java/de/danoeh/antennapod/model/feed/FeedMedia.java
index 991b5f3db..9d9c2246a 100644
--- a/model/src/main/java/de/danoeh/antennapod/model/feed/FeedMedia.java
+++ b/model/src/main/java/de/danoeh/antennapod/model/feed/FeedMedia.java
@@ -12,11 +12,13 @@ import de.danoeh.antennapod.model.MediaMetadataRetrieverCompat;
import de.danoeh.antennapod.model.playback.MediaType;
import de.danoeh.antennapod.model.playback.Playable;
import de.danoeh.antennapod.model.playback.RemoteMedia;
+import org.apache.commons.lang3.StringUtils;
+import java.io.File;
import java.util.Date;
import java.util.List;
-public class FeedMedia extends FeedFile implements Playable {
+public class FeedMedia implements Playable {
public static final int FEEDFILETYPE_FEEDMEDIA = 2;
public static final int PLAYABLE_TYPE_FEEDMEDIA = 1;
public static final String FILENAME_PREFIX_EMBEDDED_COVER = "metadata-retriever:";
@@ -33,12 +35,16 @@ public class FeedMedia extends FeedFile implements Playable {
*/
private static final int CHECKED_ON_SIZE_BUT_UNKNOWN = Integer.MIN_VALUE;
+ private long id;
+ private String localFileUrl;
+ private String downloadUrl;
+ private boolean downloaded;
private int duration;
private int position; // Current position in file
private long lastPlayedTime; // Last time this media was played (in ms)
- private int played_duration; // How many ms of this file have been played
+ private int playedDuration; // How many ms of this file have been played
private long size; // File size in Byte
- private String mime_type;
+ private String mimeType;
@Nullable private volatile FeedItem item;
private Date playbackCompletionDate;
private int startPosition = -1;
@@ -50,47 +56,50 @@ public class FeedMedia extends FeedFile implements Playable {
/* Used for loading item when restoring from parcel. */
private long itemID;
- public FeedMedia(FeedItem i, String download_url, long size,
- String mime_type) {
- super(null, download_url, false);
+ public FeedMedia(FeedItem i, String downloadUrl, long size,
+ String mimeType) {
+ this.localFileUrl = null;
+ this.downloadUrl = downloadUrl;
+ this.downloaded = false;
this.item = i;
this.size = size;
- this.mime_type = mime_type;
+ this.mimeType = mimeType;
}
public FeedMedia(long id, FeedItem item, int duration, int position,
- long size, String mime_type, String file_url, String download_url,
- boolean downloaded, Date playbackCompletionDate, int played_duration,
+ long size, String mimeType, String localFileUrl, String downloadUrl,
+ boolean downloaded, Date playbackCompletionDate, int playedDuration,
long lastPlayedTime) {
- super(file_url, download_url, downloaded);
+ this.localFileUrl = localFileUrl;
+ this.downloadUrl = downloadUrl;
+ this.downloaded = downloaded;
this.id = id;
this.item = item;
this.duration = duration;
this.position = position;
- this.played_duration = played_duration;
- this.playedDurationWhenStarted = played_duration;
+ this.playedDuration = playedDuration;
+ this.playedDurationWhenStarted = playedDuration;
this.size = size;
- this.mime_type = mime_type;
+ this.mimeType = mimeType;
this.playbackCompletionDate = playbackCompletionDate == null
? null : (Date) playbackCompletionDate.clone();
this.lastPlayedTime = lastPlayedTime;
}
public FeedMedia(long id, FeedItem item, int duration, int position,
- long size, String mime_type, String file_url, String download_url,
- boolean downloaded, Date playbackCompletionDate, int played_duration,
- Boolean hasEmbeddedPicture, long lastPlayedTime) {
- this(id, item, duration, position, size, mime_type, file_url, download_url, downloaded,
- playbackCompletionDate, played_duration, lastPlayedTime);
+ long size, String mimeType, String localFileUrl, String downloadUrl,
+ boolean downloaded, Date playbackCompletionDate, int playedDuration,
+ Boolean hasEmbeddedPicture, long lastPlayedTime) {
+ this(id, item, duration, position, size, mimeType, localFileUrl, downloadUrl, downloaded,
+ playbackCompletionDate, playedDuration, lastPlayedTime);
this.hasEmbeddedPicture = hasEmbeddedPicture;
}
- @Override
public String getHumanReadableIdentifier() {
if (item != null && item.getTitle() != null) {
return item.getTitle();
} else {
- return download_url;
+ return downloadUrl;
}
}
@@ -120,28 +129,35 @@ public class FeedMedia extends FeedFile implements Playable {
* Uses mimetype to determine the type of media.
*/
public MediaType getMediaType() {
- return MediaType.fromMimeType(mime_type);
+ return MediaType.fromMimeType(mimeType);
}
public void updateFromOther(FeedMedia other) {
- super.updateFromOther(other);
+ this.downloadUrl = other.downloadUrl;
if (other.size > 0) {
size = other.size;
}
if (other.duration > 0 && duration <= 0) { // Do not overwrite duration that we measured after downloading
duration = other.duration;
}
- if (other.mime_type != null) {
- mime_type = other.mime_type;
+ if (other.mimeType != null) {
+ mimeType = other.mimeType;
}
}
+ /**
+ * Compare's this FeedFile's attribute values with another FeedFile's
+ * attribute values. This method will only compare attributes which were
+ * read from the feed.
+ *
+ * @return true if attribute values are different, false otherwise
+ */
public boolean compareWithOther(FeedMedia other) {
- if (super.compareWithOther(other)) {
+ if (!StringUtils.equals(downloadUrl, other.downloadUrl)) {
return true;
}
- if (other.mime_type != null) {
- if (mime_type == null || !mime_type.equals(other.mime_type)) {
+ if (other.mimeType != null) {
+ if (mimeType == null || !mimeType.equals(other.mimeType)) {
return true;
}
}
@@ -154,11 +170,6 @@ public class FeedMedia extends FeedFile implements Playable {
return false;
}
- @Override
- public int getTypeAsInt() {
- return FEEDFILETYPE_FEEDMEDIA;
- }
-
public int getDuration() {
return duration;
}
@@ -173,7 +184,7 @@ public class FeedMedia extends FeedFile implements Playable {
}
public int getPlayedDuration() {
- return played_duration;
+ return playedDuration;
}
public int getPlayedDurationWhenStarted() {
@@ -181,7 +192,7 @@ public class FeedMedia extends FeedFile implements Playable {
}
public void setPlayedDuration(int played_duration) {
- this.played_duration = played_duration;
+ this.playedDuration = played_duration;
}
public int getPosition() {
@@ -229,7 +240,7 @@ public class FeedMedia extends FeedFile implements Playable {
}
public String getMime_type() {
- return mime_type;
+ return mimeType;
}
@Nullable
@@ -283,18 +294,18 @@ public class FeedMedia extends FeedFile implements Playable {
dest.writeInt(duration);
dest.writeInt(position);
dest.writeLong(size);
- dest.writeString(mime_type);
- dest.writeString(file_url);
- dest.writeString(download_url);
+ dest.writeString(mimeType);
+ dest.writeString(localFileUrl);
+ dest.writeString(downloadUrl);
dest.writeByte((byte) ((downloaded) ? 1 : 0));
dest.writeLong((playbackCompletionDate != null) ? playbackCompletionDate.getTime() : 0);
- dest.writeInt(played_duration);
+ dest.writeInt(playedDuration);
dest.writeLong(lastPlayedTime);
}
@Override
public void writeToPreferences(Editor prefEditor) {
- if(item != null && item.getFeed() != null) {
+ if (item != null && item.getFeed() != null) {
prefEditor.putLong(PREF_FEED_ID, item.getFeed().getId());
} else {
prefEditor.putLong(PREF_FEED_ID, 0L);
@@ -345,12 +356,12 @@ public class FeedMedia extends FeedFile implements Playable {
@Override
public String getLocalMediaUrl() {
- return file_url;
+ return localFileUrl;
}
@Override
public String getStreamUrl() {
- return download_url;
+ return downloadUrl;
}
public int getStartPosition() {
@@ -371,7 +382,36 @@ public class FeedMedia extends FeedFile implements Playable {
@Override
public boolean localFileAvailable() {
- return isDownloaded() && file_url != null;
+ return isDownloaded() && localFileUrl != null;
+ }
+
+ public boolean fileExists() {
+ if (localFileUrl == null) {
+ return false;
+ } else {
+ File f = new File(localFileUrl);
+ return f.exists();
+ }
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getFile_url() {
+ return localFileUrl;
+ }
+
+ public boolean isDownloaded() {
+ return downloaded;
+ }
+
+ public String getDownload_url() {
+ return downloadUrl;
}
public long getItemId() {
@@ -381,14 +421,14 @@ public class FeedMedia extends FeedFile implements Playable {
@Override
public void onPlaybackStart() {
startPosition = Math.max(position, 0);
- playedDurationWhenStarted = played_duration;
+ playedDurationWhenStarted = playedDuration;
}
@Override
public void onPlaybackPause(Context context) {
if (position > startPosition) {
- played_duration = playedDurationWhenStarted + position - startPosition;
- playedDurationWhenStarted = played_duration;
+ playedDuration = playedDurationWhenStarted + position - startPosition;
+ playedDurationWhenStarted = playedDuration;
}
startPosition = position;
}
@@ -440,17 +480,18 @@ public class FeedMedia extends FeedFile implements Playable {
this.hasEmbeddedPicture = hasEmbeddedPicture;
}
- @Override
public void setDownloaded(boolean downloaded) {
- super.setDownloaded(downloaded);
- if(item != null && downloaded && item.isNew()) {
+ this.downloaded = downloaded;
+ if (item != null && downloaded && item.isNew()) {
item.setPlayed(false);
}
}
- @Override
public void setFile_url(String file_url) {
- super.setFile_url(file_url);
+ this.localFileUrl = file_url;
+ if (file_url == null) {
+ downloaded = false;
+ }
}
public void checkEmbeddedPicture() {
diff --git a/model/src/main/java/de/danoeh/antennapod/model/feed/FeedPreferences.java b/model/src/main/java/de/danoeh/antennapod/model/feed/FeedPreferences.java
index 8e3dd48f6..02f09693e 100644
--- a/model/src/main/java/de/danoeh/antennapod/model/feed/FeedPreferences.java
+++ b/model/src/main/java/de/danoeh/antennapod/model/feed/FeedPreferences.java
@@ -40,6 +40,7 @@ public class FeedPreferences implements Serializable {
public enum NewEpisodesAction {
GLOBAL(0),
ADD_TO_INBOX(1),
+ ADD_TO_QUEUE(3),
NOTHING(2);
public final int code;
@@ -58,6 +59,25 @@ public class FeedPreferences implements Serializable {
}
}
+ public enum SkipSilence {
+ OFF(0), GLOBAL(1), AGGRESSIVE(2);
+
+ public final int code;
+
+ SkipSilence(int code) {
+ this.code = code;
+ }
+
+ public static SkipSilence fromCode(int code) {
+ for (SkipSilence s : values()) {
+ if (s.code == code) {
+ return s;
+ }
+ }
+ return GLOBAL;
+ }
+ }
+
@NonNull
private FeedFilter filter;
private long feedID;
@@ -71,6 +91,7 @@ public class FeedPreferences implements Serializable {
private float feedPlaybackSpeed;
private int feedSkipIntro;
private int feedSkipEnding;
+ private SkipSilence feedSkipSilence;
private boolean showEpisodeNotification;
private final Set<String> tags = new HashSet<>();
@@ -78,13 +99,14 @@ public class FeedPreferences implements Serializable {
VolumeAdaptionSetting volumeAdaptionSetting, NewEpisodesAction newEpisodesAction,
String username, String password) {
this(feedID, autoDownload, true, autoDeleteAction, volumeAdaptionSetting, username, password,
- new FeedFilter(), SPEED_USE_GLOBAL, 0, 0, false, newEpisodesAction, new HashSet<>());
+ new FeedFilter(), SPEED_USE_GLOBAL, 0, 0, SkipSilence.GLOBAL,
+ false, newEpisodesAction, new HashSet<>());
}
public FeedPreferences(long feedID, boolean autoDownload, boolean keepUpdated,
AutoDeleteAction autoDeleteAction, VolumeAdaptionSetting volumeAdaptionSetting,
String username, String password, @NonNull FeedFilter filter,
- float feedPlaybackSpeed, int feedSkipIntro, int feedSkipEnding,
+ float feedPlaybackSpeed, int feedSkipIntro, int feedSkipEnding, SkipSilence feedSkipSilence,
boolean showEpisodeNotification, NewEpisodesAction newEpisodesAction,
Set<String> tags) {
this.feedID = feedID;
@@ -98,6 +120,7 @@ public class FeedPreferences implements Serializable {
this.feedPlaybackSpeed = feedPlaybackSpeed;
this.feedSkipIntro = feedSkipIntro;
this.feedSkipEnding = feedSkipEnding;
+ this.feedSkipSilence = feedSkipSilence;
this.showEpisodeNotification = showEpisodeNotification;
this.newEpisodesAction = newEpisodesAction;
this.tags.addAll(tags);
@@ -240,6 +263,14 @@ public class FeedPreferences implements Serializable {
return feedSkipEnding;
}
+ public void setFeedSkipSilence(SkipSilence skipSilence) {
+ feedSkipSilence = skipSilence;
+ }
+
+ public SkipSilence getFeedSkipSilence() {
+ return feedSkipSilence;
+ }
+
public Set<String> getTags() {
return tags;
}
diff --git a/model/src/main/java/de/danoeh/antennapod/model/feed/SortOrder.java b/model/src/main/java/de/danoeh/antennapod/model/feed/SortOrder.java
index 08504b445..f6c90341a 100644
--- a/model/src/main/java/de/danoeh/antennapod/model/feed/SortOrder.java
+++ b/model/src/main/java/de/danoeh/antennapod/model/feed/SortOrder.java
@@ -72,12 +72,4 @@ public enum SortOrder {
public static String toCodeString(@Nullable SortOrder sortOrder) {
return sortOrder != null ? Integer.toString(sortOrder.code) : null;
}
-
- public static SortOrder[] valuesOf(String[] stringValues) {
- SortOrder[] values = new SortOrder[stringValues.length];
- for (int i = 0; i < stringValues.length; i++) {
- values[i] = SortOrder.valueOf(stringValues[i]);
- }
- return values;
- }
}
diff --git a/net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/DownloadRequest.java b/net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/DownloadRequest.java
index 962ecfc84..f789fda5c 100644
--- a/net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/DownloadRequest.java
+++ b/net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/DownloadRequest.java
@@ -252,7 +252,7 @@ public class DownloadRequest implements Parcelable {
this.source = UrlChecker.prepareUrl(media.getDownload_url());
this.title = media.getHumanReadableIdentifier();
this.feedfileId = media.getId();
- this.feedfileType = media.getTypeAsInt();
+ this.feedfileType = FeedMedia.FEEDFILETYPE_FEEDMEDIA;
}
public Builder(@NonNull String destination, @NonNull Feed feed) {
@@ -260,7 +260,7 @@ public class DownloadRequest implements Parcelable {
this.source = feed.isLocalFeed() ? feed.getDownload_url() : UrlChecker.prepareUrl(feed.getDownload_url());
this.title = feed.getHumanReadableIdentifier();
this.feedfileId = feed.getId();
- this.feedfileType = feed.getTypeAsInt();
+ this.feedfileType = Feed.FEEDFILETYPE_FEED;
arguments.putInt(REQUEST_ARG_PAGE_NR, feed.getPageNr());
}
diff --git a/net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/gpoddernet/GpodnetService.java b/net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/gpoddernet/GpodnetService.java
index 7873ae4fe..cfa915ffa 100644
--- a/net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/gpoddernet/GpodnetService.java
+++ b/net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/gpoddernet/GpodnetService.java
@@ -157,7 +157,7 @@ public class GpodnetService implements ISyncService {
} else {
content = "";
}
- RequestBody body = RequestBody.create(JSON, content);
+ RequestBody body = RequestBody.create(content, JSON);
Request.Builder request = new Request.Builder().post(body).url(url);
executeRequest(request);
} catch (JSONException | MalformedURLException | URISyntaxException e) {
@@ -167,38 +167,6 @@ public class GpodnetService implements ISyncService {
}
/**
- * Uploads the subscriptions of a specific device.
- * <p/>
- * This method requires authentication.
- *
- * @param deviceId The ID of the device whose subscriptions should be updated.
- * @param subscriptions A list of feed URLs containing all subscriptions of the
- * device.
- * @throws IllegalArgumentException If username, deviceId or subscriptions is null.
- * @throws GpodnetServiceAuthenticationException If there is an authentication error.
- */
- public void uploadSubscriptions(@NonNull String deviceId, @NonNull List<String> subscriptions)
- throws GpodnetServiceException {
- requireLoggedIn();
- try {
- URL url = new URI(baseScheme, null, baseHost, basePort,
- String.format("/subscriptions/%s/%s.txt", username, deviceId), null, null).toURL();
- StringBuilder builder = new StringBuilder();
- for (String s : subscriptions) {
- builder.append(s);
- builder.append("\n");
- }
- RequestBody body = RequestBody.create(TEXT, builder.toString());
- Request.Builder request = new Request.Builder().put(body).url(url);
- executeRequest(request);
- } catch (MalformedURLException | URISyntaxException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- }
-
- }
-
- /**
* Updates the subscription list of a specific device.
* <p/>
* This method requires authentication.
@@ -222,7 +190,7 @@ public class GpodnetService implements ISyncService {
requestObject.put("add", new JSONArray(added));
requestObject.put("remove", new JSONArray(removed));
- RequestBody body = RequestBody.create(JSON, requestObject.toString());
+ RequestBody body = RequestBody.create(requestObject.toString(), JSON);
Request.Builder request = new Request.Builder().post(body).url(url);
final String response = executeRequest(request);
@@ -304,7 +272,7 @@ public class GpodnetService implements ISyncService {
}
}
- RequestBody body = RequestBody.create(JSON, list.toString());
+ RequestBody body = RequestBody.create(list.toString(), JSON);
Request.Builder request = new Request.Builder().post(body).url(url);
final String response = executeRequest(request);
@@ -362,7 +330,7 @@ public class GpodnetService implements ISyncService {
e.printStackTrace();
throw new GpodnetServiceException(e);
}
- RequestBody requestBody = RequestBody.create(TEXT, "");
+ RequestBody requestBody = RequestBody.create("", TEXT);
Request request = new Request.Builder().url(url).post(requestBody).build();
try {
String credential = Credentials.basic(username, password, Charset.forName("UTF-8"));
diff --git a/net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/nextcloud/NextcloudLoginFlow.java b/net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/nextcloud/NextcloudLoginFlow.java
index 3d2374acf..254be269f 100644
--- a/net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/nextcloud/NextcloudLoginFlow.java
+++ b/net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/nextcloud/NextcloudLoginFlow.java
@@ -117,7 +117,7 @@ public class NextcloudLoginFlow {
private JSONObject doRequest(URL url, String bodyContent) throws IOException, JSONException {
RequestBody requestBody = RequestBody.create(
- MediaType.get("application/x-www-form-urlencoded"), bodyContent);
+ bodyContent, MediaType.get("application/x-www-form-urlencoded"));
Request request = new Request.Builder().url(url).method("POST", requestBody).build();
Response response = httpClient.newCall(request).execute();
if (response.code() != 200) {
diff --git a/net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/nextcloud/NextcloudSyncService.java b/net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/nextcloud/NextcloudSyncService.java
index 67b4ddab0..eaee76baf 100644
--- a/net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/nextcloud/NextcloudSyncService.java
+++ b/net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/nextcloud/NextcloudSyncService.java
@@ -71,7 +71,7 @@ public class NextcloudSyncService implements ISyncService {
requestObject.put("add", new JSONArray(addedFeeds));
requestObject.put("remove", new JSONArray(removedFeeds));
RequestBody requestBody = RequestBody.create(
- MediaType.get("application/json"), requestObject.toString());
+ requestObject.toString(), MediaType.get("application/json"));
performRequest(url, "POST", requestBody);
} catch (Exception e) {
e.printStackTrace();
@@ -121,7 +121,7 @@ public class NextcloudSyncService implements ISyncService {
}
HttpUrl.Builder url = makeUrl("/index.php/apps/gpoddersync/episode_action/create");
RequestBody requestBody = RequestBody.create(
- MediaType.get("application/json"), list.toString());
+ list.toString(), MediaType.get("application/json"));
performRequest(url, "POST", requestBody);
} catch (Exception e) {
e.printStackTrace();
diff --git a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Atom.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Atom.java
index a79556c2c..863f65d48 100644
--- a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Atom.java
+++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Atom.java
@@ -108,9 +108,9 @@ public class Atom extends Namespace {
* feed-object has no link yet b) type of link is
* LINK_TYPE_HTML or LINK_TYPE_XHTML
*/
- if (state.getFeed() != null &&
- ((type == null && state.getFeed().getLink() == null) ||
- (LINK_TYPE_HTML.equals(type) || LINK_TYPE_XHTML.equals(type)))) {
+ if (state.getFeed() != null
+ && ((type == null && state.getFeed().getLink() == null)
+ || (LINK_TYPE_HTML.equals(type) || LINK_TYPE_XHTML.equals(type)))) {
state.getFeed().setLink(href);
} else if (LINK_TYPE_ATOM.equals(type) || LINK_TYPE_RSS.equals(type)) {
// treat as podlove alternate feed
@@ -188,17 +188,17 @@ public class Atom extends Namespace {
} else if (ENTRY.equals(second) && state.getCurrentItem() != null) {
state.getCurrentItem().setTitle(textElement.getProcessedContent());
}
- } else if (SUBTITLE.equals(top) && FEED.equals(second) && textElement != null &&
- state.getFeed() != null) {
+ } else if (SUBTITLE.equals(top) && FEED.equals(second) && textElement != null
+ && state.getFeed() != null) {
state.getFeed().setDescription(textElement.getProcessedContent());
- } else if (CONTENT.equals(top) && ENTRY.equals(second) && textElement != null &&
- state.getCurrentItem() != null) {
+ } else if (CONTENT.equals(top) && ENTRY.equals(second) && textElement != null
+ && state.getCurrentItem() != null) {
state.getCurrentItem().setDescriptionIfLonger(textElement.getProcessedContent());
} else if (SUMMARY.equals(top) && ENTRY.equals(second) && textElement != null
&& state.getCurrentItem() != null) {
state.getCurrentItem().setDescriptionIfLonger(textElement.getProcessedContent());
- } else if (UPDATED.equals(top) && ENTRY.equals(second) && state.getCurrentItem() != null &&
- state.getCurrentItem().getPubDate() == null) {
+ } else if (UPDATED.equals(top) && ENTRY.equals(second) && state.getCurrentItem() != null
+ && state.getCurrentItem().getPubDate() == null) {
state.getCurrentItem().setPubDate(DateUtils.parseOrNullIfFuture(content));
} else if (PUBLISHED.equals(top) && ENTRY.equals(second) && state.getCurrentItem() != null) {
state.getCurrentItem().setPubDate(DateUtils.parseOrNullIfFuture(content));
@@ -206,8 +206,8 @@ public class Atom extends Namespace {
state.getFeed().setImageUrl(content);
} else if (IMAGE_ICON.equals(top) && state.getFeed() != null) {
state.getFeed().setImageUrl(content);
- } else if (AUTHOR_NAME.equals(top) && AUTHOR.equals(second) &&
- state.getFeed() != null && state.getCurrentItem() == null) {
+ } else if (AUTHOR_NAME.equals(top) && AUTHOR.equals(second)
+ && state.getFeed() != null && state.getCurrentItem() == null) {
String currentName = state.getFeed().getAuthor();
if (currentName == null) {
state.getFeed().setAuthor(content);
diff --git a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/DublinCore.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/DublinCore.java
index 7e2f68a17..ead449845 100644
--- a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/DublinCore.java
+++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/DublinCore.java
@@ -22,8 +22,8 @@ public class DublinCore extends Namespace {
@Override
public void handleElementEnd(String localName, HandlerState state) {
- if (state.getCurrentItem() != null && state.getContentBuf() != null &&
- state.getTagstack() != null && state.getTagstack().size() >= 2) {
+ if (state.getCurrentItem() != null && state.getContentBuf() != null
+ && state.getTagstack() != null && state.getTagstack().size() >= 2) {
FeedItem currentItem = state.getCurrentItem();
String top = state.getTagstack().peek().getName();
String second = state.getSecondTag().getName();
diff --git a/playback/base/src/main/java/de/danoeh/antennapod/playback/base/PlaybackServiceMediaPlayer.java b/playback/base/src/main/java/de/danoeh/antennapod/playback/base/PlaybackServiceMediaPlayer.java
index 73b38c00c..39ee99884 100644
--- a/playback/base/src/main/java/de/danoeh/antennapod/playback/base/PlaybackServiceMediaPlayer.java
+++ b/playback/base/src/main/java/de/danoeh/antennapod/playback/base/PlaybackServiceMediaPlayer.java
@@ -151,6 +151,8 @@ public abstract class PlaybackServiceMediaPlayer {
*/
public abstract float getPlaybackSpeed();
+ public abstract boolean getSkipSilence();
+
/**
* Sets the playback volume.
* This method is executed on an internal executor service.
diff --git a/playback/cast/build.gradle b/playback/cast/build.gradle
index 3025a369c..ac5de0e6b 100644
--- a/playback/cast/build.gradle
+++ b/playback/cast/build.gradle
@@ -18,6 +18,6 @@ dependencies {
implementation "org.greenrobot:eventbus:$eventbusVersion"
annotationProcessor "org.greenrobot:eventbus-annotation-processor:$eventbusVersion"
- playApi 'androidx.mediarouter:mediarouter:1.2.5'
+ playApi 'androidx.mediarouter:mediarouter:1.3.0'
playApi 'com.google.android.gms:play-services-cast-framework:21.2.0'
}
diff --git a/playback/cast/src/play/java/de/danoeh/antennapod/playback/cast/CastPsmp.java b/playback/cast/src/play/java/de/danoeh/antennapod/playback/cast/CastPsmp.java
index 8f0738e53..fd70fa18c 100644
--- a/playback/cast/src/play/java/de/danoeh/antennapod/playback/cast/CastPsmp.java
+++ b/playback/cast/src/play/java/de/danoeh/antennapod/playback/cast/CastPsmp.java
@@ -428,6 +428,12 @@ public class CastPsmp extends PlaybackServiceMediaPlayer {
}
@Override
+ public boolean getSkipSilence() {
+ // Don't think this is supported
+ return false;
+ }
+
+ @Override
public void setVolume(float volumeLeft, float volumeRight) {
Log.d(TAG, "Setting the Stream volume on Remote Media Player");
remoteMediaClient.setStreamVolume(volumeLeft);
diff --git a/scripts/createScreenshots.sh b/scripts/createScreenshots.sh
new file mode 100644
index 000000000..a33aa6e26
--- /dev/null
+++ b/scripts/createScreenshots.sh
@@ -0,0 +1,126 @@
+#!/bin/bash
+
+################### Create emulator ###################
+export JAVA_HOME=/usr/lib/jvm/java-8-openjdk
+echo no | $ANDROID_HOME/tools/bin/avdmanager create avd --force --name "AntennaPodScreenshots" --abi google_apis/x86_64 --package 'system-images;android-30;google_apis;x86_64'
+echo "
+disk.dataPartition.size=6G
+hw.battery=yes
+hw.cpu.ncore=4
+hw.lcd.density=420
+hw.lcd.width=1080
+hw.lcd.height=1920
+hw.ramSize=1536
+showDeviceFrame=no
+" >> $HOME/.android/avd/AntennaPodScreenshots.avd/config.ini
+nohup $ANDROID_HOME/emulator/emulator -avd AntennaPodScreenshots -no-snapshot &
+while [ "$(adb shell getprop sys.boot_completed)" != "1" ]
+do
+ echo "Waiting for emulator"
+ sleep 3
+done
+sleep 10
+
+################### Create screenshots ###################
+export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
+adb root
+
+adb uninstall de.danoeh.antennapod.debug
+./gradlew :app:installPlayDebug
+adb shell am start -n "de.danoeh.antennapod.debug/de.danoeh.antennapod.activity.MainActivity"
+sleep 1
+adb shell am force-stop de.danoeh.antennapod.debug
+version=$(adb shell dumpsys package de.danoeh.antennapod.debug | grep versionName | cut -d'=' -f2)
+versionMajor=0$(echo $version | cut -d'.' -f1)
+versionMinor=0$(echo $version | cut -d'.' -f2)
+
+wget "https://github.com/AntennaPod/Branding/raw/master/Screenshots/ScreenshotsDatabaseExport.db" -O ScreenshotsDatabaseExport.db
+
+function resetDatabase() {
+ theme=$1
+ adb shell am force-stop de.danoeh.antennapod.debug
+ adb shell rm /data/data/de.danoeh.antennapod.debug/databases/Antennapod.db-journal
+ adb push ScreenshotsDatabaseExport.db /data/data/de.danoeh.antennapod.debug/databases/Antennapod.db
+ adb shell chmod 777 /data/data/de.danoeh.antennapod.debug/databases
+ adb shell chmod 777 /data/data/de.danoeh.antennapod.debug/databases/Antennapod.db
+ echo "<?xml version='1.0' encoding='utf-8' standalone='yes' ?><map><boolean name='prefMainActivityIsFirstLaunch' value='false' /></map>" > tmp
+ adb push tmp /data/data/de.danoeh.antennapod.debug/shared_prefs/MainActivityPrefs.xml
+ echo "<?xml version='1.0' encoding='utf-8' standalone='yes' ?><map>
+ <string name='prefTheme'>$theme</string>
+ <long name='de.danoeh.antennapod.preferences.currentlyPlayingMedia' value='1' />
+ <long name='FeedMedia.PrefMediaId' value='2432' />
+ </map>" > tmp
+ adb push tmp /data/data/de.danoeh.antennapod.debug/shared_prefs/de.danoeh.antennapod.debug_preferences.xml
+ rm tmp
+ sleep 1
+}
+
+function screenshot() {
+ filename=$1
+ sleep 6
+ adb exec-out screencap -p > $filename
+}
+
+function switchLanguage() {
+ language=$1
+ adb shell "setprop persist.sys.locale $language; setprop ctl.restart zygote"
+ sleep 10
+ adb shell settings put global sysui_demo_allowed 1
+ adb shell am broadcast -a com.android.systemui.demo -e command enter
+ adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm $versionMajor$versionMinor
+ adb shell am broadcast -a com.android.systemui.demo -e command notifications -e visible false
+ adb shell am broadcast -a com.android.systemui.demo -e command network -e wifi show --es fully true -e level 4
+ adb shell am broadcast -a com.android.systemui.demo -e command network -e mobile show -e datatype lte -e level 4
+ adb shell am broadcast -a com.android.systemui.demo -e command battery -e level 100 -e plugged false
+ sleep 2
+}
+
+function createScreenshots() {
+ language=$1
+ mkdir -p "screenshots/$language"
+ switchLanguage $language
+
+ resetDatabase 0
+ adb shell am start -n "de.danoeh.antennapod.debug/de.danoeh.antennapod.activity.MainActivity" --es "fragment_tag" "SubscriptionFragment"
+ screenshot "screenshots/$language/00.png"
+
+ resetDatabase 0
+ adb shell am start -n "de.danoeh.antennapod.debug/de.danoeh.antennapod.activity.MainActivity" --es "fragment_tag" "QueueFragment"
+ sleep 1
+ adb shell am start -n "de.danoeh.antennapod.debug/de.danoeh.antennapod.activity.MainActivity" --ez "open_player" "true"
+ screenshot "screenshots/$language/01.png"
+
+ resetDatabase 0
+ adb shell am start -n "de.danoeh.antennapod.debug/de.danoeh.antennapod.activity.MainActivity" --es "fragment_tag" "QueueFragment"
+ sleep 1
+ adb shell am start -n "de.danoeh.antennapod.debug/de.danoeh.antennapod.activity.MainActivity" --ez "open_drawer" "true"
+ screenshot "screenshots/$language/02.png"
+
+ resetDatabase 0
+ adb shell am start -n "de.danoeh.antennapod.debug/de.danoeh.antennapod.activity.MainActivity" --es "fragment_tag" "EpisodesFragment"
+ screenshot "screenshots/$language/03a.png"
+
+ resetDatabase 1
+ adb shell am start -n "de.danoeh.antennapod.debug/de.danoeh.antennapod.activity.MainActivity" --es "fragment_tag" "EpisodesFragment"
+ screenshot "screenshots/$language/03b.png"
+
+ resetDatabase 0
+ adb shell am start -n "de.danoeh.antennapod.debug/de.danoeh.antennapod.activity.MainActivity" --es "fragment_tag" "QueueFragment"
+ screenshot "screenshots/$language/04.png"
+}
+
+createScreenshots "en-US"
+createScreenshots "de-DE"
+createScreenshots "es-ES"
+createScreenshots "fr-FR"
+createScreenshots "he-IL"
+createScreenshots "it-IT"
+createScreenshots "nl-NL"
+
+switchLanguage "en-US"
+adb shell settings put global sysui_demo_allowed 0
+
+################### Delete emulator ###################
+adb devices | grep emulator | cut -f1 | while read line; do adb -s $line emu kill && sleep 10; done
+$ANDROID_HOME/tools/bin/avdmanager delete avd -n "AntennaPodScreenshots"
+
diff --git a/settings.gradle b/settings.gradle
index 1e97f7fe2..5e7e973f4 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,3 +1,20 @@
+pluginManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ maven { url "https://jitpack.io" }
+ }
+}
+
include ':app'
include ':core'
include ':event'
@@ -17,6 +34,7 @@ include ':playback:base'
include ':playback:cast'
include ':storage:database'
+include ':storage:importexport'
include ':storage:preferences'
include ':ui:app-start-intent'
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBUpgrader.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBUpgrader.java
index cbac417a9..b7aec5b39 100644
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBUpgrader.java
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBUpgrader.java
@@ -334,6 +334,10 @@ class DBUpgrader {
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ " ADD COLUMN " + PodDBAdapter.KEY_NEW_EPISODES_ACTION + " INTEGER DEFAULT 0");
}
+ if (oldVersion < 3040000) {
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ + " ADD COLUMN " + PodDBAdapter.KEY_FEED_SKIP_SILENCE + " INTEGER");
+ }
}
}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java
index ccef19dc1..e577896be 100644
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java
@@ -52,7 +52,7 @@ public class PodDBAdapter {
private static final String TAG = "PodDBAdapter";
public static final String DATABASE_NAME = "Antennapod.db";
- public static final int VERSION = 3010000;
+ public static final int VERSION = 3040000;
/**
* Maximum number of arguments for IN-operator.
@@ -113,6 +113,7 @@ public class PodDBAdapter {
public static final String KEY_EXCLUDE_FILTER = "exclude_filter";
public static final String KEY_MINIMAL_DURATION_FILTER = "minimal_duration_filter";
public static final String KEY_FEED_PLAYBACK_SPEED = "feed_playback_speed";
+ public static final String KEY_FEED_SKIP_SILENCE = "feed_skip_silence";
public static final String KEY_FEED_SKIP_INTRO = "feed_skip_intro";
public static final String KEY_FEED_SKIP_ENDING = "feed_skip_ending";
public static final String KEY_FEED_TAGS = "tags";
@@ -155,6 +156,7 @@ public class PodDBAdapter {
+ KEY_LAST_UPDATE_FAILED + " INTEGER DEFAULT 0,"
+ KEY_AUTO_DELETE_ACTION + " INTEGER DEFAULT 0,"
+ KEY_FEED_PLAYBACK_SPEED + " REAL DEFAULT " + SPEED_USE_GLOBAL + ","
+ + KEY_FEED_SKIP_SILENCE + " INTEGER DEFAULT " + FeedPreferences.SkipSilence.GLOBAL.code + ","
+ KEY_FEED_VOLUME_ADAPTION + " INTEGER DEFAULT 0,"
+ KEY_FEED_TAGS + " TEXT,"
+ KEY_FEED_SKIP_INTRO + " INTEGER DEFAULT 0,"
@@ -307,6 +309,7 @@ public class PodDBAdapter {
+ TABLE_NAME_FEEDS + "." + KEY_EXCLUDE_FILTER + ", "
+ TABLE_NAME_FEEDS + "." + KEY_MINIMAL_DURATION_FILTER + ", "
+ TABLE_NAME_FEEDS + "." + KEY_FEED_PLAYBACK_SPEED + ", "
+ + TABLE_NAME_FEEDS + "." + KEY_FEED_SKIP_SILENCE + ", "
+ TABLE_NAME_FEEDS + "." + KEY_FEED_TAGS + ", "
+ TABLE_NAME_FEEDS + "." + KEY_FEED_SKIP_INTRO + ", "
+ TABLE_NAME_FEEDS + "." + KEY_FEED_SKIP_ENDING + ", "
@@ -416,7 +419,7 @@ public class PodDBAdapter {
values.put(KEY_FILE_URL, feed.getFile_url());
values.put(KEY_DOWNLOAD_URL, feed.getDownload_url());
values.put(KEY_DOWNLOADED, feed.isDownloaded());
- values.put(KEY_LASTUPDATE, feed.getLastUpdate());
+ values.put(KEY_LASTUPDATE, feed.getLastModified());
values.put(KEY_TYPE, feed.getType());
values.put(KEY_FEED_IDENTIFIER, feed.getFeedIdentifier());
@@ -456,6 +459,7 @@ public class PodDBAdapter {
values.put(KEY_EXCLUDE_FILTER, prefs.getFilter().getExcludeFilterRaw());
values.put(KEY_MINIMAL_DURATION_FILTER, prefs.getFilter().getMinimalDurationFilter());
values.put(KEY_FEED_PLAYBACK_SPEED, prefs.getFeedPlaybackSpeed());
+ values.put(KEY_FEED_SKIP_SILENCE, prefs.getFeedSkipSilence().code);
values.put(KEY_FEED_TAGS, prefs.getTagsAsString());
values.put(KEY_FEED_SKIP_INTRO, prefs.getFeedSkipIntro());
values.put(KEY_FEED_SKIP_ENDING, prefs.getFeedSkipEnding());
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedPreferencesCursorMapper.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedPreferencesCursorMapper.java
index 2de100dff..83b62b8a3 100644
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedPreferencesCursorMapper.java
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedPreferencesCursorMapper.java
@@ -31,6 +31,7 @@ public abstract class FeedPreferencesCursorMapper {
int indexExcludeFilter = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_EXCLUDE_FILTER);
int indexMinimalDurationFilter = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_MINIMAL_DURATION_FILTER);
int indexFeedPlaybackSpeed = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_PLAYBACK_SPEED);
+ int indexFeedSkipSilence = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_SKIP_SILENCE);
int indexAutoSkipIntro = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_SKIP_INTRO);
int indexAutoSkipEnding = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_SKIP_ENDING);
int indexEpisodeNotification = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_EPISODE_NOTIFICATION);
@@ -52,6 +53,8 @@ public abstract class FeedPreferencesCursorMapper {
float feedPlaybackSpeed = cursor.getFloat(indexFeedPlaybackSpeed);
int feedAutoSkipIntro = cursor.getInt(indexAutoSkipIntro);
int feedAutoSkipEnding = cursor.getInt(indexAutoSkipEnding);
+ FeedPreferences.SkipSilence feedSkipSilence =
+ FeedPreferences.SkipSilence.fromCode(cursor.getInt(indexFeedSkipSilence));
FeedPreferences.NewEpisodesAction feedNewEpisodesAction =
FeedPreferences.NewEpisodesAction.fromCode(cursor.getInt(indexNewEpisodesAction));
boolean showNotification = cursor.getInt(indexEpisodeNotification) > 0;
@@ -59,6 +62,7 @@ public abstract class FeedPreferencesCursorMapper {
if (TextUtils.isEmpty(tagsString)) {
tagsString = FeedPreferences.TAG_ROOT;
}
+
return new FeedPreferences(feedId,
autoDownload,
autoRefresh,
@@ -70,6 +74,7 @@ public abstract class FeedPreferencesCursorMapper {
feedPlaybackSpeed,
feedAutoSkipIntro,
feedAutoSkipEnding,
+ feedSkipSilence,
showNotification,
feedNewEpisodesAction,
new HashSet<>(Arrays.asList(tagsString.split(FeedPreferences.TAG_SEPARATOR))));
diff --git a/storage/importexport/README.md b/storage/importexport/README.md
new file mode 100644
index 000000000..925d537d3
--- /dev/null
+++ b/storage/importexport/README.md
@@ -0,0 +1,3 @@
+# :storage:importexport
+
+Import/Export of the AntennaPod database.
diff --git a/storage/importexport/build.gradle b/storage/importexport/build.gradle
new file mode 100644
index 000000000..ddbbd1951
--- /dev/null
+++ b/storage/importexport/build.gradle
@@ -0,0 +1,21 @@
+plugins {
+ id("com.android.library")
+}
+apply from: "../../common.gradle"
+
+android {
+ namespace "de.danoeh.antennapod.storage.importexport"
+}
+
+dependencies {
+ implementation project(':storage:database')
+ implementation project(':storage:preferences')
+ implementation project(':ui:i18n')
+ implementation project(':model')
+
+ annotationProcessor "androidx.annotation:annotation:$annotationVersion"
+ implementation "commons-io:commons-io:$commonsioVersion"
+ implementation "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
+ implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
+ implementation 'androidx.documentfile:documentfile:1.0.1'
+}
diff --git a/core/src/main/assets/html-export-favorites-item-template.html b/storage/importexport/src/main/assets/html-export-favorites-item-template.html
index 83f06a458..83f06a458 100644
--- a/core/src/main/assets/html-export-favorites-item-template.html
+++ b/storage/importexport/src/main/assets/html-export-favorites-item-template.html
diff --git a/core/src/main/assets/html-export-feed-template.html b/storage/importexport/src/main/assets/html-export-feed-template.html
index 0646d5953..0646d5953 100644
--- a/core/src/main/assets/html-export-feed-template.html
+++ b/storage/importexport/src/main/assets/html-export-feed-template.html
diff --git a/core/src/main/assets/html-export-template.html b/storage/importexport/src/main/assets/html-export-template.html
index e4d3ffd31..9137ccd65 100644
--- a/core/src/main/assets/html-export-template.html
+++ b/storage/importexport/src/main/assets/html-export-template.html
@@ -16,6 +16,7 @@
background-image: linear-gradient(180deg, #0f9cff, #0682ff);
text-align: center;
padding: 10px;
+ min-height: 100%;
}
h1 {
color: #fff;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DatabaseExporter.java b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/DatabaseExporter.java
index d4a863b8b..d152ba34a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DatabaseExporter.java
+++ b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/DatabaseExporter.java
@@ -1,4 +1,4 @@
-package de.danoeh.antennapod.core.storage;
+package de.danoeh.antennapod.storage.importexport;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
@@ -7,7 +7,6 @@ import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.text.format.Formatter;
import android.util.Log;
-import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.storage.database.PodDBAdapter;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/FavoritesWriter.java
index 649ec815a..280cd1028 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java
+++ b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/FavoritesWriter.java
@@ -1,9 +1,8 @@
-package de.danoeh.antennapod.core.export.favorites;
+package de.danoeh.antennapod.storage.importexport;
import android.content.Context;
import android.util.Log;
-import de.danoeh.antennapod.model.feed.FeedItemFilter;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
@@ -14,21 +13,17 @@ import java.util.List;
import java.util.Map;
import java.util.TreeMap;
-import de.danoeh.antennapod.core.export.ExportWriter;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedItem;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.model.feed.SortOrder;
/** Writes saved favorites to file. */
-public class FavoritesWriter implements ExportWriter {
+public class FavoritesWriter {
private static final String TAG = "FavoritesWriter";
private static final String FAVORITE_TEMPLATE = "html-export-favorites-item-template.html";
private static final String FEED_TEMPLATE = "html-export-feed-template.html";
private static final String UTF_8 = "UTF-8";
- @Override
- public void writeDocument(List<Feed> feeds, Writer writer, Context context)
+ public static void writeDocument(List<FeedItem> allFavorites, Writer writer, Context context)
throws IllegalArgumentException, IllegalStateException, IOException {
Log.d(TAG, "Starting to write document");
@@ -43,8 +38,6 @@ public class FavoritesWriter implements ExportWriter {
InputStream feedTemplateStream = context.getAssets().open(FEED_TEMPLATE);
String feedTemplate = IOUtils.toString(feedTemplateStream, UTF_8);
- List<FeedItem> allFavorites = DBReader.getEpisodes(0, Integer.MAX_VALUE,
- new FeedItemFilter(FeedItemFilter.IS_FAVORITE), SortOrder.DATE_NEW_OLD);
Map<Long, List<FeedItem>> favoriteByFeed = getFeedMap(allFavorites);
writer.append(templateParts[0]);
@@ -72,7 +65,7 @@ public class FavoritesWriter implements ExportWriter {
* @param favoritesList {@code List} of all favorite episodes.
* @return A {@code Map} favorite episodes, keyed by feed ID.
*/
- private Map<Long, List<FeedItem>> getFeedMap(List<FeedItem> favoritesList) {
+ private static Map<Long, List<FeedItem>> getFeedMap(List<FeedItem> favoritesList) {
Map<Long, List<FeedItem>> feedMap = new TreeMap<>();
for (FeedItem item : favoritesList) {
@@ -89,7 +82,7 @@ public class FavoritesWriter implements ExportWriter {
return feedMap;
}
- private void writeFeed(Writer writer, Feed feed, String feedTemplate) throws IOException {
+ private static void writeFeed(Writer writer, Feed feed, String feedTemplate) throws IOException {
String feedInfo = feedTemplate
.replace("{FEED_IMG}", feed.getImageUrl())
.replace("{FEED_TITLE}", feed.getTitle())
@@ -99,7 +92,7 @@ public class FavoritesWriter implements ExportWriter {
writer.append(feedInfo);
}
- private void writeFavoriteItem(Writer writer, FeedItem item, String favoriteTemplate) throws IOException {
+ private static void writeFavoriteItem(Writer writer, FeedItem item, String favoriteTemplate) throws IOException {
String favItem = favoriteTemplate.replace("{FAV_TITLE}", item.getTitle().trim());
if (item.getLink() != null) {
favItem = favItem.replace("{FAV_WEBSITE}", item.getLink());
@@ -114,9 +107,4 @@ public class FavoritesWriter implements ExportWriter {
writer.append(favItem);
}
-
- @Override
- public String fileExtension() {
- return "html";
- }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlWriter.java b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/HtmlWriter.java
index 8a660600f..6ad1feb3d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlWriter.java
+++ b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/HtmlWriter.java
@@ -1,8 +1,7 @@
-package de.danoeh.antennapod.core.export.html;
+package de.danoeh.antennapod.storage.importexport;
import android.content.Context;
import android.util.Log;
-import de.danoeh.antennapod.core.export.ExportWriter;
import de.danoeh.antennapod.model.feed.Feed;
import java.io.IOException;
import java.io.InputStream;
@@ -11,15 +10,14 @@ import java.util.List;
import org.apache.commons.io.IOUtils;
/** Writes HTML documents. */
-public class HtmlWriter implements ExportWriter {
+public class HtmlWriter {
private static final String TAG = "HtmlWriter";
/**
* Takes a list of feeds and a writer and writes those into an HTML
* document.
*/
- @Override
- public void writeDocument(List<Feed> feeds, Writer writer, Context context)
+ public static void writeDocument(List<Feed> feeds, Writer writer, Context context)
throws IllegalArgumentException, IllegalStateException, IOException {
Log.d(TAG, "Starting to write document");
@@ -43,9 +41,4 @@ public class HtmlWriter implements ExportWriter {
writer.append(templateParts[1]);
Log.d(TAG, "Finished writing document");
}
-
- public String fileExtension() {
- return "html";
- }
-
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlElement.java b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlElement.java
index e4ba08440..c644ae43e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlElement.java
+++ b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlElement.java
@@ -1,4 +1,4 @@
-package de.danoeh.antennapod.core.export.opml;
+package de.danoeh.antennapod.storage.importexport;
/**
* Represents a single feed in an OPML file.
diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlReader.java b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlReader.java
index 81bd0b79c..e5165d63b 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlReader.java
+++ b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlReader.java
@@ -1,8 +1,9 @@
-package de.danoeh.antennapod.core.export.opml;
+package de.danoeh.antennapod.storage.importexport;
import android.text.TextUtils;
import android.util.Log;
+import de.danoeh.antennapod.storage.preferences.BuildConfig;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
@@ -11,8 +12,6 @@ import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
-import de.danoeh.antennapod.core.BuildConfig;
-
/**
* Reads OPML documents.
*/
diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlSymbols.java b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlSymbols.java
index 0cdfd0d87..886650230 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlSymbols.java
+++ b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlSymbols.java
@@ -1,12 +1,14 @@
-package de.danoeh.antennapod.core.export.opml;
-
-import de.danoeh.antennapod.core.export.CommonSymbols;
+package de.danoeh.antennapod.storage.importexport;
/**
* Contains symbols for reading and writing OPML documents.
*/
-final class OpmlSymbols extends CommonSymbols {
+final class OpmlSymbols {
+ public static final String XML_FEATURE_INDENT_OUTPUT = "http://xmlpull.org/v1/doc/features.html#indent-output";
+ public static final String HEAD = "head";
+ public static final String BODY = "body";
+ public static final String TITLE = "title";
public static final String OPML = "opml";
static final String OUTLINE = "outline";
static final String TEXT = "text";
@@ -19,5 +21,4 @@ final class OpmlSymbols extends CommonSymbols {
private OpmlSymbols() {
}
-
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlWriter.java b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlWriter.java
index a44d90557..75be4bffe 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlWriter.java
+++ b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlWriter.java
@@ -1,22 +1,21 @@
-package de.danoeh.antennapod.core.export.opml;
+package de.danoeh.antennapod.storage.importexport;
-import android.content.Context;
import android.util.Log;
import android.util.Xml;
-import de.danoeh.antennapod.core.util.DateFormatter;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.Writer;
+import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
+import java.util.Locale;
-import de.danoeh.antennapod.core.export.ExportWriter;
import de.danoeh.antennapod.model.feed.Feed;
/** Writes OPML documents. */
-public class OpmlWriter implements ExportWriter {
+public class OpmlWriter {
private static final String TAG = "OpmlWriter";
private static final String ENCODING = "UTF-8";
@@ -27,8 +26,7 @@ public class OpmlWriter implements ExportWriter {
* Takes a list of feeds and a writer and writes those into an OPML
* document.
*/
- @Override
- public void writeDocument(List<Feed> feeds, Writer writer, Context context)
+ public static void writeDocument(List<Feed> feeds, Writer writer)
throws IllegalArgumentException, IllegalStateException, IOException {
Log.d(TAG, "Starting to write document");
XmlSerializer xs = Xml.newSerializer();
@@ -44,7 +42,7 @@ public class OpmlWriter implements ExportWriter {
xs.text(OPML_TITLE);
xs.endTag(null, OpmlSymbols.TITLE);
xs.startTag(null, OpmlSymbols.DATE_CREATED);
- xs.text(DateFormatter.formatRfc822Date(new Date()));
+ xs.text(formatRfc822Date(new Date()));
xs.endTag(null, OpmlSymbols.DATE_CREATED);
xs.endTag(null, OpmlSymbols.HEAD);
@@ -68,8 +66,8 @@ public class OpmlWriter implements ExportWriter {
Log.d(TAG, "Finished writing document");
}
- public String fileExtension() {
- return "opml";
+ private static String formatRfc822Date(Date date) {
+ SimpleDateFormat format = new SimpleDateFormat("dd MMM yy HH:mm:ss Z", Locale.US);
+ return format.format(date);
}
-
}
diff --git a/storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java b/storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java
index b454ee5a1..a42493692 100644
--- a/storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java
+++ b/storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java
@@ -6,17 +6,13 @@ import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.app.NotificationCompat;
import androidx.preference.PreferenceManager;
-import de.danoeh.antennapod.model.download.ProxyConfig;
-import de.danoeh.antennapod.model.feed.FeedCounter;
-import de.danoeh.antennapod.model.feed.FeedPreferences;
-import de.danoeh.antennapod.model.feed.SortOrder;
-import de.danoeh.antennapod.model.feed.SubscriptionsFilter;
-import de.danoeh.antennapod.model.playback.MediaType;
+
import org.json.JSONArray;
import org.json.JSONException;
@@ -32,6 +28,13 @@ import java.util.List;
import java.util.Locale;
import java.util.Set;
+import de.danoeh.antennapod.model.download.ProxyConfig;
+import de.danoeh.antennapod.model.feed.FeedCounter;
+import de.danoeh.antennapod.model.feed.FeedPreferences;
+import de.danoeh.antennapod.model.feed.SortOrder;
+import de.danoeh.antennapod.model.feed.SubscriptionsFilter;
+import de.danoeh.antennapod.model.playback.MediaType;
+
/**
* Provides access to preferences set by the user in the settings screen. A
* private instance of this class must first be instantiated via
@@ -130,9 +133,9 @@ public class UserPreferences {
public static final int NOTIFICATION_BUTTON_REWIND = 0;
public static final int NOTIFICATION_BUTTON_FAST_FORWARD = 1;
public static final int NOTIFICATION_BUTTON_SKIP = 2;
-
public static final int NOTIFICATION_BUTTON_NEXT_CHAPTER = 3;
public static final int NOTIFICATION_BUTTON_PLAYBACK_SPEED = 4;
+ public static final int NOTIFICATION_BUTTON_SLEEP_TIMER = 5;
public static final int EPISODE_CACHE_SIZE_UNLIMITED = -1;
public static final int FEED_ORDER_COUNTER = 0;
public static final int FEED_ORDER_ALPHABETICAL = 1;
@@ -235,6 +238,10 @@ public class UserPreferences {
return showButtonOnFullNotification(NOTIFICATION_BUTTON_PLAYBACK_SPEED);
}
+ public static boolean showSleepTimerOnFullNotification() {
+ return showButtonOnFullNotification(NOTIFICATION_BUTTON_SLEEP_TIMER);
+ }
+
public static int getFeedOrder() {
String value = prefs.getString(PREF_DRAWER_FEED_ORDER, "" + FEED_ORDER_COUNTER);
return Integer.parseInt(value);
@@ -365,7 +372,9 @@ public class UserPreferences {
prefs.edit().putBoolean(UserPreferences.PREF_FOLLOW_QUEUE, value).apply();
}
- public static boolean shouldSkipKeepEpisode() { return prefs.getBoolean(PREF_SKIP_KEEPS_EPISODE, true); }
+ public static boolean shouldSkipKeepEpisode() {
+ return prefs.getBoolean(PREF_SKIP_KEEPS_EPISODE, true);
+ }
public static boolean shouldFavoriteKeepEpisode() {
return prefs.getBoolean(PREF_FAVORITE_KEEPS_EPISODE, true);
@@ -582,33 +591,23 @@ public class UserPreferences {
}
public static void setFastForwardSecs(int secs) {
- prefs.edit()
- .putInt(PREF_FAST_FORWARD_SECS, secs)
- .apply();
+ prefs.edit().putInt(PREF_FAST_FORWARD_SECS, secs).apply();
}
public static void setRewindSecs(int secs) {
- prefs.edit()
- .putInt(PREF_REWIND_SECS, secs)
- .apply();
+ prefs.edit().putInt(PREF_REWIND_SECS, secs).apply();
}
public static void setPlaybackSpeed(float speed) {
- prefs.edit()
- .putString(PREF_PLAYBACK_SPEED, String.valueOf(speed))
- .apply();
+ prefs.edit().putString(PREF_PLAYBACK_SPEED, String.valueOf(speed)).apply();
}
public static void setVideoPlaybackSpeed(float speed) {
- prefs.edit()
- .putString(PREF_VIDEO_PLAYBACK_SPEED, String.valueOf(speed))
- .apply();
+ prefs.edit().putString(PREF_VIDEO_PLAYBACK_SPEED, String.valueOf(speed)).apply();
}
public static void setSkipSilence(boolean skipSilence) {
- prefs.edit()
- .putBoolean(PREF_PLAYBACK_SKIP_SILENCE, skipSilence)
- .apply();
+ prefs.edit().putBoolean(PREF_PLAYBACK_SKIP_SILENCE, skipSilence).apply();
}
public static void setPlaybackSpeedArray(List<Float> speeds) {
@@ -619,15 +618,11 @@ public class UserPreferences {
for (float speed : speeds) {
jsonArray.put(speedFormat.format(speed));
}
- prefs.edit()
- .putString(PREF_PLAYBACK_SPEED_ARRAY, jsonArray.toString())
- .apply();
+ prefs.edit().putString(PREF_PLAYBACK_SPEED_ARRAY, jsonArray.toString()).apply();
}
public static void setAutodownloadSelectedNetworks(String[] value) {
- prefs.edit()
- .putString(PREF_AUTODL_SELECTED_NETWORKS, TextUtils.join(",", value))
- .apply();
+ prefs.edit().putString(PREF_AUTODL_SELECTED_NETWORKS, TextUtils.join(",", value)).apply();
}
public static boolean gpodnetNotificationsEnabled() {
@@ -645,29 +640,21 @@ public class UserPreferences {
}
public static void setGpodnetNotificationsEnabled() {
- prefs.edit()
- .putBoolean(PREF_GPODNET_NOTIFICATIONS, true)
- .apply();
+ prefs.edit().putBoolean(PREF_GPODNET_NOTIFICATIONS, true).apply();
}
public static void setHiddenDrawerItems(List<String> items) {
String str = TextUtils.join(",", items);
- prefs.edit()
- .putString(PREF_HIDDEN_DRAWER_ITEMS, str)
- .apply();
+ prefs.edit().putString(PREF_HIDDEN_DRAWER_ITEMS, str).apply();
}
public static void setFullNotificationButtons(List<Integer> items) {
String str = TextUtils.join(",", items);
- prefs.edit()
- .putString(PREF_FULL_NOTIFICATION_BUTTONS, str)
- .apply();
+ prefs.edit().putString(PREF_FULL_NOTIFICATION_BUTTONS, str).apply();
}
public static void setQueueLocked(boolean locked) {
- prefs.edit()
- .putBoolean(PREF_QUEUE_LOCKED, locked)
- .apply();
+ prefs.edit().putBoolean(PREF_QUEUE_LOCKED, locked).apply();
}
private static List<Float> readPlaybackSpeedArray(String valueFromPrefs) {
@@ -693,9 +680,7 @@ public class UserPreferences {
}
public static void setEpisodeCleanupValue(int episodeCleanupValue) {
- prefs.edit()
- .putString(PREF_EPISODE_CLEANUP, Integer.toString(episodeCleanupValue))
- .apply();
+ prefs.edit().putString(PREF_EPISODE_CLEANUP, Integer.toString(episodeCleanupValue)).apply();
}
/**
@@ -741,9 +726,7 @@ public class UserPreferences {
public static void setDataFolder(String dir) {
Log.d(TAG, "setDataFolder(dir: " + dir + ")");
- prefs.edit()
- .putString(PREF_DATA_FOLDER, dir)
- .apply();
+ prefs.edit().putString(PREF_DATA_FOLDER, dir).apply();
}
/**
@@ -801,9 +784,7 @@ public class UserPreferences {
* @see #setQueueKeepSortedOrder(SortOrder)
*/
public static void setQueueKeepSorted(boolean keepSorted) {
- prefs.edit()
- .putBoolean(PREF_QUEUE_KEEP_SORTED, keepSorted)
- .apply();
+ prefs.edit().putBoolean(PREF_QUEUE_KEEP_SORTED, keepSorted).apply();
}
/**
@@ -826,9 +807,7 @@ public class UserPreferences {
if (sortOrder == null) {
return;
}
- prefs.edit()
- .putString(PREF_QUEUE_KEEP_SORTED_ORDER, sortOrder.name())
- .apply();
+ prefs.edit().putString(PREF_QUEUE_KEEP_SORTED_ORDER, sortOrder.name()).apply();
}
public static FeedPreferences.NewEpisodesAction getNewEpisodesAction() {
@@ -867,9 +846,7 @@ public class UserPreferences {
}
public static void setSubscriptionsFilter(SubscriptionsFilter value) {
- prefs.edit()
- .putString(PREF_FILTER_FEED, value.serialize())
- .apply();
+ prefs.edit().putString(PREF_FILTER_FEED, value.serialize()).apply();
}
public static boolean shouldShowSubscriptionTitle() {
diff --git a/ui/common/src/main/java/de/danoeh/antennapod/ui/common/PagedToolbarFragment.java b/ui/common/src/main/java/de/danoeh/antennapod/ui/common/PagedToolbarFragment.java
index 3d82cb32c..48793ff13 100644
--- a/ui/common/src/main/java/de/danoeh/antennapod/ui/common/PagedToolbarFragment.java
+++ b/ui/common/src/main/java/de/danoeh/antennapod/ui/common/PagedToolbarFragment.java
@@ -1,6 +1,5 @@
package de.danoeh.antennapod.ui.common;
-import androidx.annotation.NonNull;
import com.google.android.material.appbar.MaterialToolbar;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.widget.ViewPager2;
@@ -10,23 +9,8 @@ import androidx.viewpager2.widget.ViewPager2;
* All items share the same general menu items and are just allowed to show/hide them.
*/
public abstract class PagedToolbarFragment extends Fragment {
- private MaterialToolbar toolbar;
- private ViewPager2 viewPager;
- /**
- * Invalidate the toolbar menu if the current child fragment is visible.
- * @param child The fragment to invalidate
- */
- public void invalidateOptionsMenuIfActive(@NonNull Fragment child) {
- Fragment visibleChild = getChildFragmentManager().findFragmentByTag("f" + viewPager.getCurrentItem());
- if (visibleChild == child) {
- visibleChild.onPrepareOptionsMenu(toolbar.getMenu());
- }
- }
-
- protected void setupPagedToolbar(MaterialToolbar toolbar, ViewPager2 viewPager) {
- this.toolbar = toolbar;
- this.viewPager = viewPager;
+ protected void setupPagedToolbar(final MaterialToolbar toolbar, final ViewPager2 viewPager) {
toolbar.setOnMenuItemClickListener(item -> {
if (this.onOptionsItemSelected(item)) {
diff --git a/ui/common/src/main/java/de/danoeh/antennapod/ui/common/TriangleLabelView.java b/ui/common/src/main/java/de/danoeh/antennapod/ui/common/TriangleLabelView.java
deleted file mode 100644
index 97bcede2f..000000000
--- a/ui/common/src/main/java/de/danoeh/antennapod/ui/common/TriangleLabelView.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2016 Shota Saito
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Source: https://github.com/shts/TriangleLabelView
- * Modified for our need; see AntennaPod #5925 for context
- */
-
-package de.danoeh.antennapod.ui.common;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-import android.util.AttributeSet;
-import android.view.View;
-
-public class TriangleLabelView extends View {
-
- private static final int DEGREES_LEFT = -45;
- private static final int DEGREES_RIGHT = 45;
- private final PaintHolder primary = new PaintHolder();
- private float topPadding;
- private float bottomPadding;
- private float centerPadding;
- private Paint trianglePaint;
- private int width;
- private int height;
- private Corner corner;
-
- public TriangleLabelView(final Context context) {
- this(context, null);
- }
-
- public TriangleLabelView(final Context context, final AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public TriangleLabelView(final Context context, final AttributeSet attrs,
- final int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(context, attrs);
- }
-
- public TriangleLabelView(final Context context, final AttributeSet attrs,
- final int defStyleAttr, final int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- init(context, attrs);
- }
-
- private void init(final Context context, final AttributeSet attrs) {
- final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TriangleLabelView);
-
- this.topPadding = ta.getDimension(R.styleable.TriangleLabelView_labelTopPadding, dp2px(7));
- this.centerPadding = ta.getDimension(R.styleable.TriangleLabelView_labelCenterPadding, dp2px(3));
- this.bottomPadding = ta.getDimension(R.styleable.TriangleLabelView_labelBottomPadding, dp2px(3));
-
- final int backgroundColor = ta.getColor(R.styleable.TriangleLabelView_backgroundColor,
- Color.parseColor("#66000000"));
- this.primary.color = ta.getColor(R.styleable.TriangleLabelView_primaryTextColor, Color.WHITE);
-
- this.primary.size = ta.getDimension(R.styleable.TriangleLabelView_primaryTextSize, sp2px(11));
-
- final String primary = ta.getString(R.styleable.TriangleLabelView_primaryText);
- if (primary != null) {
- this.primary.text = primary;
- }
-
- this.corner = Corner.from(ta.getInt(R.styleable.TriangleLabelView_corner, 1));
-
- ta.recycle();
-
- this.primary.initPaint();
-
- trianglePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- trianglePaint.setColor(backgroundColor);
-
- this.primary.resetStatus();
- }
-
- public void setPrimaryText(final String text) {
- primary.text = text;
- primary.resetStatus();
- relayout();
- }
-
- public Corner getCorner() {
- return corner;
- }
-
- public void setCorner(final Corner corner) {
- this.corner = corner;
- relayout();
- }
-
- @Override
- protected void onDraw(final Canvas canvas) {
- super.onDraw(canvas);
- canvas.save();
-
- // translate
- canvas.translate(0, (float) ((height * Math.sqrt(2)) - height));
-
- // rotate
- if (corner.left()) {
- canvas.rotate(DEGREES_LEFT, 0, height);
- } else {
- canvas.rotate(DEGREES_RIGHT, width, height);
- }
-
- // draw triangle
- @SuppressLint("DrawAllocation")
- final Path path = new Path();
- path.moveTo(0, height);
- path.lineTo(width / 2f, 0);
- path.lineTo(width, height);
- path.close();
- canvas.drawPath(path, trianglePaint);
-
- // draw primaryText
- canvas.drawText(primary.text, (width) / 2f,
- (topPadding + centerPadding + primary.height), primary.paint);
- canvas.restore();
- }
-
- @Override
- protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- height = (int) (topPadding + centerPadding + bottomPadding + primary.height);
- width = 2 * height;
- final int realHeight = (int) (height * Math.sqrt(2));
- setMeasuredDimension(width, realHeight);
- }
-
- public int dp2px(final float dpValue) {
- final float scale = getContext().getResources().getDisplayMetrics().density;
- return (int) (dpValue * scale + 0.5f);
- }
-
- public float sp2px(final float spValue) {
- final float scale = getContext().getResources().getDisplayMetrics().scaledDensity;
- return spValue * scale;
- }
-
- /**
- * Should be called whenever what we're displaying could have changed.
- */
- private void relayout() {
- invalidate();
- requestLayout();
- }
-
- public enum Corner {
- TOP_LEFT(1),
- TOP_RIGHT(2);
- private final int type;
-
- Corner(final int type) {
- this.type = type;
- }
-
- private static Corner from(final int type) {
- for (final Corner c : values()) {
- if (c.type == type) {
- return c;
- }
- }
- return Corner.TOP_LEFT;
- }
-
- private boolean left() {
- return this == TOP_LEFT;
- }
- }
-
- private static class PaintHolder {
- String text = "";
- Paint paint;
- int color;
- float size;
- float height;
- float width;
-
- void initPaint() {
- paint = new Paint(Paint.ANTI_ALIAS_FLAG);
- paint.setColor(color);
- paint.setTextAlign(Paint.Align.CENTER);
- paint.setTextSize(size);
- paint.setTypeface(Typeface.DEFAULT_BOLD);
- }
-
- void resetStatus() {
- final Rect rectText = new Rect();
- paint.getTextBounds(text, 0, text.length(), rectText);
- width = rectText.width();
- height = rectText.height();
- }
- }
-}
diff --git a/ui/common/src/main/res/values/attrs.xml b/ui/common/src/main/res/values/attrs.xml
deleted file mode 100644
index f3334fe77..000000000
--- a/ui/common/src/main/res/values/attrs.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <declare-styleable name="TriangleLabelView">
- <attr name="backgroundColor" format="color" />
- <attr name="primaryTextColor" format="color" />
- <attr name="primaryText" format="string" />
- <attr name="primaryTextSize" format="dimension" />
-
- <attr name="labelTopPadding" format="dimension" />
- <attr name="labelCenterPadding" format="dimension" />
- <attr name="labelBottomPadding" format="dimension" />
-
- <attr name="corner">
- <enum name="leftTop" value="1" />
- <enum name="rightTop" value="2" />
- </attr>
- </declare-styleable>
-</resources>
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/EchoActivity.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/EchoActivity.java
index 758eaeac7..5981c7ad4 100644
--- a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/EchoActivity.java
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/EchoActivity.java
@@ -222,7 +222,7 @@ public class EchoActivity extends AppCompatActivity {
long secondsPerDay = queueSecondsLeft / daysUntilNextYear;
String timePerDay = Converter.getDurationStringLocalized(
getLocalizedResources(this, getEchoLanguage()), secondsPerDay * 1000, true);
- double hoursPerDay = (double) (secondsPerDay / 3600);
+ double hoursPerDay = secondsPerDay / 3600.0;
int nextYear = RELEASE_YEAR + 1;
if (hoursPerDay < 1.5) {
viewBinding.aboveLabel.setText(R.string.echo_queue_title_clean);
diff --git a/ui/glide/src/main/java/de/danoeh/antennapod/ui/glide/ApOkHttpUrlLoader.java b/ui/glide/src/main/java/de/danoeh/antennapod/ui/glide/ApOkHttpUrlLoader.java
index 5c3605594..3814c0700 100644
--- a/ui/glide/src/main/java/de/danoeh/antennapod/ui/glide/ApOkHttpUrlLoader.java
+++ b/ui/glide/src/main/java/de/danoeh/antennapod/ui/glide/ApOkHttpUrlLoader.java
@@ -104,7 +104,7 @@ class ApOkHttpUrlLoader implements ModelLoader<String, InputStream> {
.protocol(Protocol.HTTP_2)
.code(420)
.message("Policy Not Fulfilled")
- .body(ResponseBody.create(null, new byte[0]))
+ .body(ResponseBody.create(new byte[0], null))
.request(chain.request())
.build();
}
diff --git a/ui/glide/src/main/java/de/danoeh/antennapod/ui/glide/FastBlurTransformation.java b/ui/glide/src/main/java/de/danoeh/antennapod/ui/glide/FastBlurTransformation.java
index a19611100..54040e4b4 100644
--- a/ui/glide/src/main/java/de/danoeh/antennapod/ui/glide/FastBlurTransformation.java
+++ b/ui/glide/src/main/java/de/danoeh/antennapod/ui/glide/FastBlurTransformation.java
@@ -12,7 +12,7 @@ import java.nio.charset.Charset;
import java.security.MessageDigest;
public class FastBlurTransformation extends BitmapTransformation {
- private static final String ID = "de.danoeh.antennapod.core.glide.FastBlurTransformation";
+ private static final String ID = "de.danoeh.antennapod.ui.glide.FastBlurTransformation";
private static final String TAG = FastBlurTransformation.class.getSimpleName();
diff --git a/ui/i18n/src/main/res/values/strings.xml b/ui/i18n/src/main/res/values/strings.xml
index e40e03035..b07d6c45f 100644
--- a/ui/i18n/src/main/res/values/strings.xml
+++ b/ui/i18n/src/main/res/values/strings.xml
@@ -138,6 +138,7 @@
<string name="feed_auto_download_always">Always</string>
<string name="feed_auto_download_never">Never</string>
<string name="feed_new_episodes_action_add_to_inbox">Add to inbox</string>
+ <string name="feed_new_episodes_action_add_to_queue">Add to queue</string>
<string name="feed_new_episodes_action_nothing">Nothing</string>
<string name="episode_cleanup_never">Never</string>
<string name="episode_cleanup_except_favorite_removal">When not favorited</string>
@@ -193,7 +194,7 @@
<string name="select_all_above">Select all above</string>
<string name="select_all_below">Select all below</string>
<string name="filtered_label">Filtered</string>
- <string name="refresh_failed_msg">{fa-exclamation-circle} Last refresh failed. Tap to view details.</string>
+ <string name="refresh_failed_msg">Last refresh failed. Tap to view details.</string>
<string name="open_podcast">Open podcast</string>
<string name="please_wait_for_data">Please wait until the data is loaded</string>
<string name="updates_disabled_label">Updates disabled</string>
@@ -319,11 +320,6 @@
<!-- Mediaplayer messages -->
<string name="playback_error_generic"><![CDATA[The media file could not be played.\n\n- Try deleting and re-downloading the episode.\n- Check your network connection, and make sure no VPN or login page is blocking access.\n- Try long-pressing and sharing the \"Media address\" to your web browser to see if it can be played there. If not, contact the podcast creators.]]></string>
- <string name="playback_error_server_died">Server died</string>
- <string name="playback_error_unsupported">Unsupported media type</string>
- <string name="playback_error_timeout">Operation timed out</string>
- <string name="playback_error_source">Unable to access media file</string>
- <string name="playback_error_unknown">Unknown error</string>
<string name="no_media_playing_label">No media playing</string>
<string name="position_default_label" translatable="false">00:00:00</string>
<string name="unknown_media_key">AntennaPod - Unknown media key: %1$d</string>
@@ -488,9 +484,9 @@
<string name="pref_expandNotify_sum">This usually expands the notification to show playback buttons.</string>
<string name="pref_persistNotify_title">Persistent playback controls</string>
<string name="pref_persistNotify_sum">Keep notification and lockscreen controls when playback is paused</string>
- <string name="pref_compact_notification_buttons_dialog_error_exact">You must select exactly %1$d items.</string>
+ <string name="pref_compact_notification_buttons_dialog_error_exact">You must select exactly two items</string>
<string name="pref_full_notification_buttons_title">Set notification buttons</string>
- <string name="pref_full_notification_buttons_sum">Change the playback buttons on the playback notification.</string>
+ <string name="pref_full_notification_buttons_sum">Change the buttons on the playback notification</string>
<string name="pref_enqueue_location_title">Enqueue location</string>
<string name="pref_enqueue_location_sum">Add episodes to: %1$s</string>
<string name="enqueue_location_back">Back</string>
@@ -707,7 +703,7 @@
<string name="feed_tags_label">Tags</string>
<string name="feed_tags_summary">Change the tags of this podcast to help organize your subscriptions</string>
<string name="feed_folders_include_root">Show this podcast in main list</string>
- <string name="multi_feed_common_tags_info">{fa-info-circle} Only common tags from all selected subscriptions are shown. Other tags stay unaffected.</string>
+ <string name="multi_feed_common_tags_info">Only common tags from all selected subscriptions are shown. Other tags stay unaffected.</string>
<string name="auto_download_settings_label">Auto download settings</string>
<string name="episode_filters_label">Episode filter</string>
<string name="episode_filters_description">List of terms used to decide if an episode should be included or excluded when auto downloading</string>
@@ -723,11 +719,29 @@
<string name="statistics_episodes_on_device">Episodes on the device:</string>
<string name="statistics_space_used">Space used:</string>
<string name="statistics_episodes_started_total">Episodes started/total:</string>
+ <string name="statistics_expected_next_episode">Expected next episode:</string>
+ <string name="statistics_expected_next_episode_any_day">Any day now</string>
+ <string name="statistics_expected_next_episode_unknown">Unknown</string>
<string name="statistics_view_all">View for all podcasts »</string>
- <string name="wait_icon" translatable="false">{fa-spinner}</string>
+ <string name="wait_icon" translatable="false">…</string>
<string name="edit_url_menu">Edit feed URL</string>
<string name="edit_url_confirmation_msg">Changing the RSS address can easily break the playback state and episode listings of the podcast. We do NOT recommend changing it and will NOT provide support if anything goes wrong. This cannot be undone. The broken subscription CANNOT be repaired by simply changing the address back. We suggest creating a backup before continuing.</string>
+ <!-- Podcast release schedules -->
+ <string name="release_schedule_daily">daily</string>
+ <string name="release_schedule_weekdays">on weekdays</string>
+ <string name="release_schedule_weekly">weekly</string>
+ <string name="release_schedule_biweekly">every two weeks</string>
+ <string name="release_schedule_monthly">monthly</string>
+
+ <string name="release_schedule_monday">Mon</string>
+ <string name="release_schedule_tuesday">Tue</string>
+ <string name="release_schedule_wednesday">Wed</string>
+ <string name="release_schedule_thursday">Thu</string>
+ <string name="release_schedule_friday">Fri</string>
+ <string name="release_schedule_saturday">Sat</string>
+ <string name="release_schedule_sunday">Sun</string>
+
<!-- AntennaPodSP -->
<string name="sp_apps_importing_feeds_msg">Importing subscriptions from single-purpose apps&#8230;</string>
diff --git a/ui/png-icons/src/main/res/drawable/ic_notification_sleep.xml b/ui/png-icons/src/main/res/drawable/ic_notification_sleep.xml
new file mode 100644
index 000000000..60cfbb616
--- /dev/null
+++ b/ui/png-icons/src/main/res/drawable/ic_notification_sleep.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp"
+ android:viewportHeight="24.0" android:viewportWidth="24.0"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#ffffff" android:pathData="M23,12H17V10L20.39,6H17V4H23V6L19.62,10H23V12M15,16H9V14L12.39,10H9V8H15V10L11.62,14H15V16M7,20H1V18L4.39,14H1V12H7V14L3.62,18H7V20Z"/>
+</vector>
diff --git a/ui/png-icons/src/main/res/drawable/ic_notification_sleep_off.xml b/ui/png-icons/src/main/res/drawable/ic_notification_sleep_off.xml
new file mode 100644
index 000000000..8cb32124b
--- /dev/null
+++ b/ui/png-icons/src/main/res/drawable/ic_notification_sleep_off.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp"
+ android:viewportHeight="24.0" android:viewportWidth="24.0"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#ffffff" android:pathData="M2,5.27L3.28,4L20,20.72L18.73,22L12.73,16H9V14L9.79,13.06L2,5.27M23,12H17V10L20.39,6H17V4H23V6L19.62,10H23V12M9.82,8H15V10L13.54,11.72L9.82,8M7,20H1V18L4.39,14H1V12H7V14L3.62,18H7V20Z"/>
+</vector>
diff --git a/ui/statistics/build.gradle b/ui/statistics/build.gradle
index 7dafcba55..f49b98a4e 100644
--- a/ui/statistics/build.gradle
+++ b/ui/statistics/build.gradle
@@ -27,6 +27,4 @@ dependencies {
implementation "com.github.bumptech.glide:glide:$glideVersion"
implementation "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
- implementation "com.joanzapata.iconify:android-iconify-fontawesome:$iconifyVersion"
- implementation "com.joanzapata.iconify:android-iconify-material:$iconifyVersion"
}
diff --git a/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/feed/FeedStatisticsFragment.java b/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/feed/FeedStatisticsFragment.java
index 1aeeb8fa9..a7916ac5a 100644
--- a/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/feed/FeedStatisticsFragment.java
+++ b/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/feed/FeedStatisticsFragment.java
@@ -2,6 +2,7 @@ package de.danoeh.antennapod.ui.statistics.feed;
import android.os.Bundle;
import android.text.format.Formatter;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -11,13 +12,23 @@ import androidx.fragment.app.Fragment;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.StatisticsItem;
import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.core.util.DateFormatter;
+import de.danoeh.antennapod.core.util.ReleaseScheduleGuesser;
+import de.danoeh.antennapod.model.feed.FeedItem;
+import de.danoeh.antennapod.model.feed.FeedItemFilter;
+import de.danoeh.antennapod.model.feed.SortOrder;
+import de.danoeh.antennapod.ui.statistics.R;
import de.danoeh.antennapod.ui.statistics.databinding.FeedStatisticsBinding;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
+import java.util.ArrayList;
+import java.util.Calendar;
import java.util.Collections;
+import java.util.Date;
+import java.util.List;
import java.util.Locale;
public class FeedStatisticsFragment extends Fragment {
@@ -66,7 +77,17 @@ public class FeedStatisticsFragment extends Fragment {
for (StatisticsItem statisticsItem : statisticsData.feedTime) {
if (statisticsItem.feed.getId() == feedId) {
- return statisticsItem;
+ List<FeedItem> items = DBReader.getFeedItemList(statisticsItem.feed,
+ FeedItemFilter.unfiltered(), SortOrder.DATE_OLD_NEW);
+ List<Date> dates = new ArrayList<>();
+ for (FeedItem item : items) {
+ dates.add(item.getPubDate());
+ }
+ ReleaseScheduleGuesser.Guess guess = null;
+ if (dates.size() > 1) {
+ guess = ReleaseScheduleGuesser.performGuess(dates);
+ }
+ return new Pair<>(statisticsItem, guess);
}
}
return null;
@@ -76,13 +97,80 @@ public class FeedStatisticsFragment extends Fragment {
.subscribe(this::showStats, Throwable::printStackTrace);
}
- private void showStats(StatisticsItem s) {
+ private String getReadableDay(int day) {
+ switch (day) {
+ case Calendar.MONDAY:
+ return getString(R.string.release_schedule_monday);
+ case Calendar.TUESDAY:
+ return getString(R.string.release_schedule_tuesday);
+ case Calendar.WEDNESDAY:
+ return getString(R.string.release_schedule_wednesday);
+ case Calendar.THURSDAY:
+ return getString(R.string.release_schedule_thursday);
+ case Calendar.FRIDAY:
+ return getString(R.string.release_schedule_friday);
+ case Calendar.SATURDAY:
+ return getString(R.string.release_schedule_saturday);
+ case Calendar.SUNDAY:
+ return getString(R.string.release_schedule_sunday);
+ default:
+ return "error";
+ }
+ }
+
+ private String getReadableSchedule(ReleaseScheduleGuesser.Guess guess) {
+ switch (guess.schedule) {
+ case DAILY:
+ return getString(R.string.release_schedule_daily);
+ case WEEKDAYS:
+ return getString(R.string.release_schedule_weekdays);
+ case WEEKLY:
+ return getString(R.string.release_schedule_weekly) + ", " + getReadableDay(guess.days.get(0));
+ case BIWEEKLY:
+ return getString(R.string.release_schedule_biweekly) + ", " + getReadableDay(guess.days.get(0));
+ case MONTHLY:
+ return getString(R.string.release_schedule_monthly);
+ case FOURWEEKLY:
+ return getString(R.string.release_schedule_monthly) + ", " + getReadableDay(guess.days.get(0));
+ case SPECIFIC_DAYS:
+ StringBuilder days = new StringBuilder();
+ for (int i = 0; i < guess.days.size(); i++) {
+ if (i != 0) {
+ days.append(", ");
+ }
+ days.append(getReadableDay(guess.days.get(i)));
+ }
+ return days.toString();
+ default:
+ return getString(R.string.statistics_expected_next_episode_unknown);
+ }
+ }
+
+ private void showStats(Pair<StatisticsItem, ReleaseScheduleGuesser.Guess> p) {
+ StatisticsItem s = p.first;
viewBinding.startedTotalLabel.setText(String.format(Locale.getDefault(), "%d / %d",
s.episodesStarted, s.episodes));
viewBinding.timePlayedLabel.setText(Converter.shortLocalizedDuration(getContext(), s.timePlayed));
viewBinding.totalDurationLabel.setText(Converter.shortLocalizedDuration(getContext(), s.time));
viewBinding.onDeviceLabel.setText(String.format(Locale.getDefault(), "%d", s.episodesDownloadCount));
viewBinding.spaceUsedLabel.setText(Formatter.formatShortFileSize(getContext(), s.totalDownloadSize));
+
+ ReleaseScheduleGuesser.Guess guess = p.second;
+ if (!s.feed.getPreferences().getKeepUpdated()) {
+ viewBinding.expectedNextEpisodeLabel.setText(R.string.updates_disabled_label);
+ } else if (guess == null || guess.nextExpectedDate.getTime() <= new Date().getTime() - 7 * 24 * 3600000L) {
+ // More than 30 days delayed
+ viewBinding.expectedNextEpisodeLabel.setText(R.string.statistics_expected_next_episode_unknown);
+ } else {
+ String text = DateFormatter.formatAbbrev(getContext(), guess.nextExpectedDate);
+ if (guess.nextExpectedDate.getTime() <= new Date().getTime()) {
+ text = getString(R.string.statistics_expected_next_episode_any_day);
+ }
+ if (guess.schedule != ReleaseScheduleGuesser.Schedule.UNKNOWN) {
+ text += " (" + getReadableSchedule(guess) + ")";
+ }
+ viewBinding.expectedNextEpisodeLabel.setText(text);
+ }
}
@Override
diff --git a/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/years/BarChartView.java b/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/years/BarChartView.java
index eadbb29ee..93b9e3332 100644
--- a/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/years/BarChartView.java
+++ b/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/years/BarChartView.java
@@ -49,7 +49,7 @@ public class BarChartView extends AppCompatImageView {
drawable.data = data;
drawable.maxValue = 1;
for (DBReader.MonthlyStatisticsItem item : data) {
- drawable.maxValue = Math.max(drawable.maxValue, item.timePlayed);
+ drawable.maxValue = Math.max(drawable.maxValue, item.getTimePlayed());
}
}
@@ -89,21 +89,21 @@ public class BarChartView extends AppCompatImageView {
paintBars.setStrokeWidth(height * 0.015f);
paintBars.setColor(colors[0]);
int colorIndex = 0;
- int lastYear = data.size() > 0 ? data.get(0).year : 0;
+ int lastYear = data.size() > 0 ? data.get(0).getYear() : 0;
for (int i = 0; i < data.size(); i++) {
float x = textPadding + (i + 1) * stepSize;
- if (lastYear != data.get(i).year) {
- lastYear = data.get(i).year;
+ if (lastYear != data.get(i).getYear()) {
+ lastYear = data.get(i).getYear();
colorIndex++;
paintBars.setColor(colors[colorIndex % 2]);
if (i < data.size() - 2) {
- canvas.drawText(String.valueOf(data.get(i).year), x + stepSize,
+ canvas.drawText(String.valueOf(data.get(i).getYear()), x + stepSize,
barHeight + (height - barHeight + textSize) / 2, paintGridText);
}
canvas.drawLine(x, height, x, barHeight, paintGridText);
}
- float valuePercentage = (float) Math.max(0.005, (float) data.get(i).timePlayed / maxValue);
+ float valuePercentage = (float) Math.max(0.005, (float) data.get(i).getTimePlayed() / maxValue);
float y = (1 - valuePercentage) * barHeight;
canvas.drawRect(x, y, x + stepSize * 0.95f, barHeight, paintBars);
}
diff --git a/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/years/YearStatisticsListAdapter.java b/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/years/YearStatisticsListAdapter.java
index 2116a17a4..d000ceb62 100644
--- a/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/years/YearStatisticsListAdapter.java
+++ b/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/years/YearStatisticsListAdapter.java
@@ -57,41 +57,41 @@ public class YearStatisticsListAdapter extends RecyclerView.Adapter<RecyclerView
} else {
StatisticsHolder holder = (StatisticsHolder) h;
DBReader.MonthlyStatisticsItem statsItem = yearlyAggregate.get(position - 1);
- holder.year.setText(String.format(Locale.getDefault(), "%d ", statsItem.year));
- holder.hours.setText(String.format(Locale.getDefault(), "%.1f ", statsItem.timePlayed / 3600000.0f)
+ holder.year.setText(String.format(Locale.getDefault(), "%d ", statsItem.getYear()));
+ holder.hours.setText(String.format(Locale.getDefault(), "%.1f ", statsItem.getTimePlayed() / 3600000.0f)
+ context.getString(R.string.time_hours));
}
}
public void update(List<DBReader.MonthlyStatisticsItem> statistics) {
- int lastYear = statistics.size() > 0 ? statistics.get(0).year : 0;
- int lastDataPoint = statistics.size() > 0 ? (statistics.get(0).month - 1) + lastYear * 12 : 0;
+ int lastYear = statistics.size() > 0 ? statistics.get(0).getYear() : 0;
+ int lastDataPoint = statistics.size() > 0 ? (statistics.get(0).getMonth() - 1) + lastYear * 12 : 0;
long yearSum = 0;
yearlyAggregate.clear();
statisticsData.clear();
for (DBReader.MonthlyStatisticsItem statistic : statistics) {
- if (statistic.year != lastYear) {
+ if (statistic.getYear() != lastYear) {
DBReader.MonthlyStatisticsItem yearAggregate = new DBReader.MonthlyStatisticsItem();
- yearAggregate.year = lastYear;
- yearAggregate.timePlayed = yearSum;
+ yearAggregate.setYear(lastYear);
+ yearAggregate.setTimePlayed(yearSum);
yearlyAggregate.add(yearAggregate);
yearSum = 0;
- lastYear = statistic.year;
+ lastYear = statistic.getYear();
}
- yearSum += statistic.timePlayed;
- while (lastDataPoint + 1 < (statistic.month - 1) + statistic.year * 12) {
+ yearSum += statistic.getTimePlayed();
+ while (lastDataPoint + 1 < (statistic.getMonth() - 1) + statistic.getYear() * 12) {
lastDataPoint++;
DBReader.MonthlyStatisticsItem item = new DBReader.MonthlyStatisticsItem();
- item.year = lastDataPoint / 12;
- item.month = lastDataPoint % 12 + 1;
+ item.setYear(lastDataPoint / 12);
+ item.setMonth(lastDataPoint % 12 + 1);
statisticsData.add(item); // Compensate for months without playback
}
statisticsData.add(statistic);
- lastDataPoint = (statistic.month - 1) + statistic.year * 12;
+ lastDataPoint = (statistic.getMonth() - 1) + statistic.getYear() * 12;
}
DBReader.MonthlyStatisticsItem yearAggregate = new DBReader.MonthlyStatisticsItem();
- yearAggregate.year = lastYear;
- yearAggregate.timePlayed = yearSum;
+ yearAggregate.setYear(lastYear);
+ yearAggregate.setTimePlayed(yearSum);
yearlyAggregate.add(yearAggregate);
Collections.reverse(yearlyAggregate);
notifyDataSetChanged();
diff --git a/ui/statistics/src/main/res/layout/feed_statistics.xml b/ui/statistics/src/main/res/layout/feed_statistics.xml
index 6b9a7fa4c..02afb0161 100644
--- a/ui/statistics/src/main/res/layout/feed_statistics.xml
+++ b/ui/statistics/src/main/res/layout/feed_statistics.xml
@@ -11,12 +11,14 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:text="@string/statistics_episodes_started_total" />
- <com.joanzapata.iconify.widget.IconTextView
+ <TextView
android:id="@+id/startedTotalLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:text="@string/wait_icon"
@@ -29,12 +31,14 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:text="@string/statistics_time_played" />
- <com.joanzapata.iconify.widget.IconTextView
+ <TextView
android:id="@+id/timePlayedLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:text="@string/wait_icon"
@@ -48,12 +52,14 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:text="@string/statistics_total_duration" />
- <com.joanzapata.iconify.widget.IconTextView
+ <TextView
android:id="@+id/totalDurationLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:text="@string/wait_icon"
@@ -66,12 +72,14 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:text="@string/statistics_episodes_on_device" />
- <com.joanzapata.iconify.widget.IconTextView
+ <TextView
android:id="@+id/onDeviceLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:text="@string/wait_icon"
@@ -84,12 +92,14 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:text="@string/statistics_space_used" />
- <com.joanzapata.iconify.widget.IconTextView
+ <TextView
android:id="@+id/spaceUsedLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:text="@string/wait_icon"
@@ -97,4 +107,25 @@
</TableRow>
+ <TableRow>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/statistics_expected_next_episode" />
+
+ <TextView
+ android:id="@+id/expectedNextEpisodeLabel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
+ android:lines="2"
+ android:text="@string/wait_icon"
+ tools:text="Jan 1st (weekly)" />
+
+ </TableRow>
+
</TableLayout>