diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/announcements/AnnouncementsPatch.java b/app/src/main/java/app/revanced/integrations/youtube/patches/announcements/AnnouncementsPatch.java index 6f2c9e50..8de878a7 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/announcements/AnnouncementsPatch.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/announcements/AnnouncementsPatch.java @@ -6,12 +6,11 @@ import android.text.Html; import android.text.method.LinkMovementMethod; import android.widget.TextView; import androidx.annotation.RequiresApi; - +import app.revanced.integrations.shared.Logger; +import app.revanced.integrations.shared.Utils; import app.revanced.integrations.youtube.patches.announcements.requests.AnnouncementsRoutes; import app.revanced.integrations.youtube.requests.Requester; import app.revanced.integrations.youtube.settings.Settings; -import app.revanced.integrations.shared.Logger; -import app.revanced.integrations.shared.Utils; import org.json.JSONObject; import java.io.IOException; @@ -49,9 +48,10 @@ public final class AnnouncementsPatch { try { // Do not show the announcement if the request failed. if (connection.getResponseCode() != 200) { - if (Settings.ANNOUNCEMENT_LAST_HASH.get().isEmpty()) return; + if (Settings.ANNOUNCEMENT_LAST_ID.isSetToDefault()) + return; - Settings.ANNOUNCEMENT_LAST_HASH.resetToDefault(); + Settings.ANNOUNCEMENT_LAST_ID.resetToDefault(); Utils.showToastLong(str("revanced_announcements_connection_failed")); return; @@ -65,22 +65,20 @@ public final class AnnouncementsPatch { var jsonString = Requester.parseInputStreamAndClose(connection.getInputStream(), false); - // Do not show the announcement if it is older or the same as the last one. - final byte[] hashBytes = MessageDigest.getInstance("SHA-256").digest(jsonString.getBytes(StandardCharsets.UTF_8)); - final var hash = java.util.Base64.getEncoder().encodeToString(hashBytes); - if (hash.equals(Settings.ANNOUNCEMENT_LAST_HASH.get())) return; // Parse the announcement. Fall-back to raw string if it fails. + int id = Settings.ANNOUNCEMENT_LAST_ID.defaultValue; String title; String message; Level level = Level.INFO; try { final var announcement = new JSONObject(jsonString); + id = announcement.getInt("id"); title = announcement.getString("title"); message = announcement.getJSONObject("content").getString("message"); - if (!announcement.isNull("level")) level = Level.fromInt(announcement.getInt("level")); + } catch (Throwable ex) { Logger.printException(() -> "Failed to parse announcement. Fall-backing to raw string", ex); @@ -88,6 +86,28 @@ public final class AnnouncementsPatch { message = jsonString; } + // TODO: Remove this migration code after a few months. + if (!Settings.DEPRECATED_ANNOUNCEMENT_LAST_HASH.isSetToDefault()){ + final byte[] hashBytes = MessageDigest + .getInstance("SHA-256") + .digest(jsonString.getBytes(StandardCharsets.UTF_8)); + + final var hash = java.util.Base64.getEncoder().encodeToString(hashBytes); + + // Migrate to saving the id instead of the hash. + if (hash.equals(Settings.DEPRECATED_ANNOUNCEMENT_LAST_HASH.get())) { + Settings.ANNOUNCEMENT_LAST_ID.save(id); + } + + Settings.DEPRECATED_ANNOUNCEMENT_LAST_HASH.resetToDefault(); + } + + // Do not show the announcement, if the last announcement id is the same as the current one. + if (Settings.ANNOUNCEMENT_LAST_ID.get() == id) return; + + + + int finalId = id; final var finalTitle = title; final var finalMessage = Html.fromHtml(message, FROM_HTML_MODE_COMPACT); final Level finalLevel = level; @@ -99,7 +119,7 @@ public final class AnnouncementsPatch { .setMessage(finalMessage) .setIcon(finalLevel.icon) .setPositiveButton("Ok", (dialog, which) -> { - Settings.ANNOUNCEMENT_LAST_HASH.save(hash); + Settings.ANNOUNCEMENT_LAST_ID.save(finalId); dialog.dismiss(); }).setNegativeButton("Dismiss", (dialog, which) -> { dialog.dismiss(); @@ -119,18 +139,6 @@ public final class AnnouncementsPatch { }); } - /** - * Clears the last announcement hash if it is not empty. - * - * @return true if the last announcement hash was empty. - */ - private static boolean emptyLastAnnouncementHash() { - if (Settings.ANNOUNCEMENT_LAST_HASH.get().isEmpty()) return true; - Settings.ANNOUNCEMENT_LAST_HASH.resetToDefault(); - - return false; - } - private static String getOrSetConsumer() { final var consumer = Settings.ANNOUNCEMENT_CONSUMER.get(); if (!consumer.isEmpty()) return consumer; diff --git a/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java b/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java index e011f941..7967f6a7 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java +++ b/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java @@ -1,29 +1,17 @@ package app.revanced.integrations.youtube.settings; -import static java.lang.Boolean.FALSE; -import static java.lang.Boolean.TRUE; -import static app.revanced.integrations.shared.settings.Setting.migrateFromOldPreferences; -import static app.revanced.integrations.shared.settings.Setting.migrateOldSettingToNew; -import static app.revanced.integrations.shared.settings.Setting.parent; -import static app.revanced.integrations.shared.settings.Setting.parentsAny; -import static app.revanced.integrations.youtube.sponsorblock.objects.CategoryBehaviour.IGNORE; -import static app.revanced.integrations.youtube.sponsorblock.objects.CategoryBehaviour.MANUAL_SKIP; -import static app.revanced.integrations.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY; -import static app.revanced.integrations.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY_ONCE; +import app.revanced.integrations.shared.settings.*; +import app.revanced.integrations.shared.settings.preference.SharedPrefCategory; +import app.revanced.integrations.youtube.sponsorblock.SponsorBlockSettings; import java.util.Arrays; import java.util.HashSet; import java.util.Set; -import app.revanced.integrations.shared.settings.BaseSettings; -import app.revanced.integrations.shared.settings.BooleanSetting; -import app.revanced.integrations.shared.settings.FloatSetting; -import app.revanced.integrations.shared.settings.IntegerSetting; -import app.revanced.integrations.shared.settings.LongSetting; -import app.revanced.integrations.shared.settings.Setting; -import app.revanced.integrations.shared.settings.StringSetting; -import app.revanced.integrations.shared.settings.preference.SharedPrefCategory; -import app.revanced.integrations.youtube.sponsorblock.SponsorBlockSettings; +import static app.revanced.integrations.shared.settings.Setting.*; +import static app.revanced.integrations.youtube.sponsorblock.objects.CategoryBehaviour.*; +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; public class Settings extends BaseSettings { // External downloader @@ -205,7 +193,9 @@ public class Settings extends BaseSettings { public static final BooleanSetting BYPASS_URL_REDIRECTS = new BooleanSetting("revanced_bypass_url_redirects", TRUE); public static final BooleanSetting ANNOUNCEMENTS = new BooleanSetting("revanced_announcements", TRUE); public static final StringSetting ANNOUNCEMENT_CONSUMER = new StringSetting("revanced_announcement_consumer", "", false, false); - public static final StringSetting ANNOUNCEMENT_LAST_HASH = new StringSetting("revanced_announcement_last_hash", ""); + @Deprecated + public static final StringSetting DEPRECATED_ANNOUNCEMENT_LAST_HASH = new StringSetting("revanced_announcement_last_hash", ""); + public static final IntegerSetting ANNOUNCEMENT_LAST_ID = new IntegerSetting("revanced_announcement_last_id", -1); public static final BooleanSetting REMOVE_TRACKING_QUERY_PARAMETER = new BooleanSetting("revanced_remove_tracking_query_parameter", TRUE); public static final BooleanSetting REMOVE_VIEWER_DISCRETION_DIALOG= new BooleanSetting("revanced_remove_viewer_discretion_dialog", FALSE, "revanced_remove_viewer_discretion_dialog_user_dialog_message"); @@ -245,6 +235,7 @@ public class Settings extends BaseSettings { * Do not use directly, instead use {@link SponsorBlockSettings} */ public static final StringSetting SB_PRIVATE_USER_ID = new StringSetting("sb_private_user_id_Do_Not_Share", ""); + @Deprecated public static final StringSetting DEPRECATED_SB_UUID_OLD_MIGRATION_SETTING = new StringSetting("uuid", ""); // Delete sometime in 2024 public static final IntegerSetting SB_CREATE_NEW_SEGMENT_STEP = new IntegerSetting("sb_create_new_segment_step", 150, parent(SB_ENABLED)); public static final BooleanSetting SB_VOTING_BUTTON = new BooleanSetting("sb_voting_button", FALSE, parent(SB_ENABLED));