Чи є спосіб перегляду історії сповіщень браузера Chrome?


55

Я отримую сповіщення Chrome від кількох веб-сайтів, і вони працюють, коли я навіть не відкриваю вкладки для цих сайтів.

Але іноді я отримую ці сповіщення Chrome, коли я не за столом або дивлюсь на свій ноутбук.

Оскільки деякі з цих повідомлень мені корисні, я хотів би отримати доступ до будь-якого, що я пропустив.

Чи є спосіб перегляду історії сповіщень?


1
Це не здається. Переглядаючи цю публікацію ( theverge.com/2015/10/14/9531133/… ), вони змінили свою політику сповіщень та видалили її з робочого столу, щоб розмістити її на окремих веб-сторінках. Єдине, що має доступ до нових сповіщень - це натиснути на дзвінок на сторінці google.
Террі

1
Схоже, що немає: productforums.google.com/forum/#!msg/chrome/xs9PflHTfho/… - дуже прикро.
LB--

Єдине місце, в якому я знайшов сповіщення як список, якщо веб-сайт, який його заповнює, має їх через свій веб-сайт. Здається, Chrome не збирає їх у щось подібне, chrome://notificationsі вони не встигають в ОС.
Джейсон Лідон

Прийміть правильну відповідь @paradroid
Satheesh

Відповіді:


31

Якщо у вас Mac, є спосіб! 😄

Ось як виглядатиме список сповіщень:

Ось як виглядатиме список сповіщень.

Все, що вам потрібно зробити, це:

1. У Chrome перейдіть до:

chrome://flags/

2. Шукайте:

Enable native notifications. Mac

3. Увімкніть, перезапустіть хром, ви закінчили. Насолоджуйтесь!

Редагувати:

  • Можливо, вам більше не потрібно буде робити вищезазначене.

Починаючи з Chrome 59, сповіщення, надіслані через API сповіщень або API розширень chrome.notifications, відображатимуться безпосередньо у власній системі сповіщень macOS замість власної системи Chrome. [ джерело ]


2
Це не відповідає на питання про перегляд історії сповіщень, а лише про перегляд сповіщень.
Бьорн

6
@BjornTipling Це відповідає. Він запитує, чи може він бачити сповіщення, які він пропустив під час відсутності, і мій метод робить саме це.
Есдрас Лопес

1
Якщо ви покладете посилання як коментарі, я додам їх до вашої публікації для вас, @EsdrasLopez
user418150

1
@ user418150 Я ціную це, але я отримав репутацію зараз. :) Перевірте зміни.
Есдрас Лопес

2
Основна проблема тут полягає в тому, що воно зберігає сповіщення лише у тому випадку, якщо ви не натискаєте на нього. Я кілька разів натискав на цікаву назву статті, лише щоб вона не завантажувалася, однак її все-таки видалили зі списку сповіщень. Зазвичай статті є занадто новими, щоб їх можна було гуглювати, і часто заголовок сповіщення не відповідає заголовку статті, тому він втрачається в надрах Інтернету.
iBorg

11

У MacOSX у вас буде каталог Chrome, розташований у службі підтримки бібліотеки / додатків. Відкрийте термінальну програму та запустіть наступні команди:

cd ~/Library/Application\ Support/Google/Chrome/Default/Platform\ Notifications/
ls -la

Тепер ви побачите такі файли:

drwx------@  7 visi  staff   224 Jul 13 18:16 .
drwx------  75 visi  staff  2400 Jul 15 11:05 ..
-rw-------@  1 visi  staff   759 Jul 15 10:57 000003.log
-rw-------@  1 visi  staff    16 Jul 13 18:16 CURRENT
-rw-------@  1 visi  staff     0 Jul 13 18:16 LOCK
-rw-------@  1 visi  staff   147 Jul 13 18:16 LOG
-rw-------@  1 visi  staff    41 Jul 13 18:16 MANIFEST-000001

Ви можете побачити найсвіжіший з них 000003.log, тому перевірте його наступною командою:

tail -n 100 000003.log

І ви побачите останні 100 елементів з цього журналу. Потім ви можете відкрити налаштування хрому та відключити сповіщення веб-сайту.

Зауважте, що якщо у вас є кілька профілів у хромі, ваш шлях може бути різним, наприклад, таким (Профіль1 замість Типово):

cd ~/Library/Application\ Support/Google/Chrome/Profile\ 1/Platform\ Notifications/

3
Це має бути прийнятою відповіддю. :)
Коді А. Рей

1
Ще працюю в 2019 році (хоча журнал потребує невеликої інтерпретації). Чудова відповідь спасибі
carpii

11

Якщо ви переходите %LocalAppData%\Google\Chrome\User Data\Default\Platform Notifications, є файл журналу попередніх повідомлень.


4
добре, але розгляньте, якщо вказати шлях як "% LocalAppData% \ Google \ Chrome \ Дані користувача \ За замовчуванням \ Сповіщення платформи" замість жорсткого коду. Він прекрасно працює на будь-якому ПК.
Дмитро Гусаров

У UserData /-folder вам, можливо, доведеться спочатку знайти свою папку профілю, наприклад "C: \ Users \ username \ AppData \ Local \ Google \ Chrome \ UserData \ Profile 1 \
Notiform

1
Ці дані є двійковими. Як її читати?
Гая

У Chrome 71 файл журналу порожній. Це в якийсь момент було відключено?
Джеймс

2
@Gaia Я задався питанням про те, що я просто зачепив якийсь хитрий код Java, який справляє прийнятну роботу при його розшифровці. Я розмістив його нижче: superuser.com/a/1410742/778383
Президент Dreamspace

3

Оскільки, здається, неможливо отримати запис про сповіщення безпосередньо, якби у мене була така ж проблема, я б обдурив, використовуючи емулятор телефону Android або телефон, як користувач, який рекомендував Pushbullet. Але є не тільки Pushbullet, є низка інших додатків, ми могли б обговорити андроїд-хитрощі для прослуховування та запису сповіщень окремою темою.

Якщо ви програміст, ви можете, можливо, вирішити свою проблему через домашнє розширення:

https://stackoverflow.com/questions/15949606/how-can-i-listen-to-notifications

"Ви можете підключити функцію webkitNotifications.createNotification так, щоразу, коли створюється повідомлення, ви запускаєте певний код."


2

Ви можете побачити історію Push Notifications. У самому нижньому правому куті екрану вашого ПК на панелі завдань є те, що схоже на спливаючу підказку, і якщо ви наведіть на неї курсор, ви побачите, що це насправді називається "сповіщення". Якщо ви натиснете цю бульбашку, вона покаже ваші непрочитані / нові електронні листи та будь-які push-повідомлення, які ви не відхиляли. Я прийшов сюди, шукаючи цю відповідь, і не знайшов її, але потім зумів опрацювати це. Я використовую Windows 10.


Так, це остання річ у Win10, але це є можливою відповіддю для Windows.
парадороїд

1

Торкніться чогось, про що було сказано трохи вище, але з поворотом, який гарантує, що ви не пропускаєте повідомлення на OSX:

  1. У правій частині основної верхньої панелі натисніть на значок сповіщення.

  2. Клацніть на шестірні (праворуч внизу екрана сповіщень)

  3. Виберіть Chrome, щоб налаштувати відображення сповіщень.

  4. За замовчуванням вибираються "Банери", і вони можуть автоматично зникати. Замість цього виберіть тип «Сповіщення», і вони залишатимуться до тих пір, поки ви не визнаєте їх!

Будь ласка :)


-1

Здається, Pushbullet може вирішити вашу проблему. Вони стверджують, що ви можете побачити пропущені сповіщення за допомогою розширення Chrome.

https://blog.pushbullet.com/2014/10/23/easily-access-your-recent-notifications-in-chrome/


Прочитайте, як рекомендувати програмне забезпечення для мінімально необхідної інформації та пропозицій щодо того, як рекомендувати програмне забезпечення для Super User. Щоб ваша відповідь була корисною, навіть якщо надані посилання переривають ці дані, слід відредагувати вашу відповідь.
Я кажу, відновіть Моніку

Гей, приємно. Я спробую це. Я фактично вже використовую Pushbullet, але не знав про це розширення Chrome.
парадироїд

Не можу знайти цю функцію. Повідомлення спливе, і в його історії немає жодного сліду.
madprops

Я переосмислив питання, і улов ось такий. Якщо на ваш телефон надійде сповіщення, кнопкодавець доставить його на робочий стіл і повідомить, що у вас є, можливо, непрочитані сповіщення (можливо, ви бачили це на своєму телефоні чи що у вас є). На які сайти ви отримуєте хромовані сповіщення? Якщо для цього є додаток, ви завжди можете його встановити, і тоді ви отримаєте сповіщення з кнопкової стрілки на робочий стіл / ноутбук / що завгодно.
Socialorganix Contentbrandmgmt

1
Функція "Сповіщення" в Pushbullet призначена лише для перегляду сповіщень з вашого Android-телефону на робочому столі, а також для iPhone, якщо у вас робочий стіл Mac. Це не має нічого спільного з сповіщеннями Chrome.
Боаз

-1

Завдяки Corey «s відповідь вище, і ледачим суботу з занадто багато часу на моїх руках, я можу тепер бачити список останніх повідомлень Chrome в консолі мого IDE, де я можу навіть натиснути на URL.

Код є хитрим і використовує грубу евристику, оскільки я не маю поняття правильного способу інтерпретації бінарних даних.

Але це на тонну краще, ніж нічого. Приклад виводу (уривок):

https://www.finanzen.net/nachricht/aktien/kw-9-tops-und-flops-der-tecdax-aktien-in-der-vergangenen-woche-7195100
https://images.finanzen.net/mediacenter/unsortiert/TecDAX_boerse_frankfurt0016_kl.jpg
So bewegten sich die Einzelwerte des TecDAX in der zurückliegenden Handelswoche.*
KW 9: Tops und Flops der TecDAX-Aktien in der vergangenen Woche
So bewegten sich die Einzelwerte des TecDAX in der zurückliegenden Handelswoche.
HideOnTheseRoutes
Home/Index;Article/News/Index
tag-7195100
NotificationIdentifier
1061622960{


https://www.youtube.com/watch?v=W-mlD_bYKdU&feature=push-u-sub&attr_tag=0SL8UpnrTOnTECxr%3A6
https://lh5.googleusercontent.com/-raJM5SITO34/AAAAAAAAAAI/AAAAAAAAAAA/UtLljlL4Wpc/s96-c-mo/photo.jpg
New from Market Moves
Trade Recap: $1,500 in PROFITS*˜
COuAyJGY4uACEAY=
attributionTag
0SL8UpnrTOnTECxr:6{
 from Market MovesTrade Recap: $1,500 in PROFITS

Ясний код розп'яття:

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;




/**
 * v[1, 2019-03-02 13:00 UTC]
 *
 * by dreamspace-president.com
 */
final public class CrappyChromeNotificationHistoryReader {


    public static void main(final String[] args) {

        final File file = new File(
                "C:\\Users\\[YOUR_NAME_HERE]\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Platform Notifications\\000003.log");

        final List<ChromeNotificationStuff> notifications = obtainChromeNotificationStuff(file);
        for (ChromeNotificationStuff notification : notifications) {
            System.err.println();
            System.err.println(notification);
        }
        System.exit(0);
    }


    public static List<ChromeNotificationStuff> obtainChromeNotificationStuff(final File file) {

        final List<ChromeNotificationStuff> ret = new ArrayList<>();

        final List<DumbTokenList> listOfDumbTokenLists = doTheInsaneParsingThing(file);
        int instanceCounter = 0;
        for (DumbTokenList dtl : listOfDumbTokenLists) {

            final List<String> urls = new ArrayList<>();
            final List<String> texts = new ArrayList<>();

            for (String token : dtl.tokens) {
                if (token.startsWith("https://") || token.startsWith("http://")) {
                    urls.add(token);
                } else {
                    texts.add(token);
                }
            }


            // Remove unimportant URLs.
            for (int i = urls.size() - 1; i > 0; i--) {
                final String urlThis = urls.get(i);
                final int lenThis = urlThis.length();
                for (int ii = i - 1; ii >= 0; ii--) {
                    final String urlThat = urls.get(ii);
                    final int lenThat = urlThat.length();

                    if (lenThis > lenThat) {
                        if (urlThis.startsWith(urlThat)) {
                            final String removed = urls.remove(ii);
                            //                            System.err.println("\nREMOVED: " + removed + "\nKEPT   : " + urlThis); // because was better or equal
                            break;
                        }
                    } else {
                        if (urlThat.startsWith(urlThis)) {
                            final String removed = urls.remove(i);
                            //                            System.err.println("\nREMOVED: " + removed + "\nKEPT   : " + urlThat); // because was better or equal
                            break;
                        }
                    }

                }
            }

            ret.add(new ChromeNotificationStuff(instanceCounter, urls, texts));
            instanceCounter++;
        }

        ret.sort(null);

        return ret;
    }


    final public static class ChromeNotificationStuff implements Comparable<ChromeNotificationStuff> {


        private final int instanceCounter;
        final public List<String> urls;
        final public List<String> texts;


        private ChromeNotificationStuff(final int instanceCounter,
                                        final List<String> urls,
                                        final List<String> texts) {

            this.instanceCounter = instanceCounter;

            this.urls = Collections.unmodifiableList(urls);
            this.texts = Collections.unmodifiableList(texts);
        }


        public String toString() {

            final StringBuilder sb = new StringBuilder();
            for (String url : urls) {
                sb.append(url).append('\n');
            }
            for (String text : texts) {
                sb.append(text).append('\n');
            }
            return sb.toString();
        }


        @Override
        public int compareTo(final ChromeNotificationStuff o) { // Newest (= last) notifications first, please.

            return Integer.compare(o.instanceCounter, instanceCounter);
        }
    }




    final private static double MIN_LENGTH_DIFFERENCE_RATIO = 0.7;//0.9;
    final private static double MIN_REMAININGLINES_PERCENTAGEOF_ALLLINES = 0.2;




    final private static class DumbTokenList {


        final private static int MIN_LENGTH = 10; //6;
        final private static String[] EXTENSIONS = new String[] { ".jpg", ".jpeg", ".png", ".gif", ".html", ".htm", ".php" };
        final private static int MAX_EXTRA_CRAP_AFTER_EXTENSIONS = 3;
        final private static String SAFE_URL_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;="; // https://stackoverflow.com/a/1547940/3500521

        final private String originalText;
        final private List<String> tokens;


        private DumbTokenList(final String textWithBinaryCrap) {

            originalText = textWithBinaryCrap;

            final List<String> tokens = new ArrayList<>();

            final Consumer<String> addTokenButTryToDecrappifyExtensionsFirstAnTing = token -> {


                if (token.startsWith("ttps://") || token.startsWith("ttp://")) {
                    token = "h" + token;
                }


                final List<String> newTokens = new ArrayList<>();

                if (token.startsWith("http")) {
                    final int tokenLength = token.length();
                    boolean found = false;
                    for (int i = 0; i < tokenLength; i++) {
                        final char c = token.charAt(i);
                        if (SAFE_URL_CHARACTERS.indexOf(c) < 0) {
                            newTokens.add(token.substring(0, i));
                            newTokens.add(token.substring(i));
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        newTokens.add(token);
                    }
                } else {
                    newTokens.add(token);
                }

                for (String newToken : newTokens) {


                    String foundExt = null;
                    int foundExtLen = 0;
                    int foundExtAt = -1;
                    for (String extension : EXTENSIONS) {
                        final int idx = newToken.indexOf(extension);
                        if (idx >= 0) {
                            final int extLen = extension.length();
                            if (idx > foundExtAt || (idx == foundExtAt && extLen > foundExtLen)) {
                                foundExt = extension;
                                foundExtLen = extLen;
                                foundExtAt = idx;
                            }
                        }
                    }
                    if (foundExt != null) {
                        final int amountOfCharactersAfterThisFind = newToken.length() - foundExtAt - foundExtLen;
                        if (amountOfCharactersAfterThisFind <= MAX_EXTRA_CRAP_AFTER_EXTENSIONS) {
                            // OK. Shorten this bitch.
                            newToken = newToken.substring(0, foundExtAt + foundExtLen);
                        }
                    }


                    if (newToken.startsWith("http")) {
                        if (!newToken.startsWith("http://") && !newToken.startsWith("https://")) {
                            continue;
                        }
                    }


                    if (newToken.startsWith("/watch?v=")) {
                        newToken = "https://www.youtube.com" + newToken;
                    }


                    if (newToken.length() >= MIN_LENGTH) {
                        tokens.add(newToken);
                    }


                }

            };

            final StringBuilder sb = new StringBuilder();

            final int len = textWithBinaryCrap.length();
            for (int i = 0; i <= len + 1; i++) {

                final char c = i < len ? textWithBinaryCrap.charAt(i) : 0;

                if (c < ' ' || c == '"') {

                    String potentialText = sb.toString();
                    while (true) {
                        final int httpIDX = potentialText.indexOf("http", 1);
                        if (httpIDX < 0) {
                            addTokenButTryToDecrappifyExtensionsFirstAnTing.accept(potentialText);
                            break;
                        } else {
                            final String snippet = potentialText.substring(0, httpIDX);
                            potentialText = potentialText.substring(httpIDX);
                            addTokenButTryToDecrappifyExtensionsFirstAnTing.accept(snippet);
                        }
                    }

                    sb.setLength(0);

                    if (c == '"') {
                        // Skip this and the next. (thus "i < len +1")
                        i++;
                    }
                } else {
                    sb.append(c);
                }
            }


            // Remove quasi-duplicates. Sue me.
            //            System.err.println("\n*** STARTING DEDUPLICATION ***");
            final int lSize = tokens.size();
            for (int i = lSize - 1; i > 0; i--) { // (not 0 itself, wouldn't make sense)

                if (i < tokens.size()) {

                    final String entry = tokens.get(i);

                    for (int ii = i - 1; ii >= 0; ii--) { // (incl. 0)

                        final String otherEntry = tokens.get(ii);

                        final Boolean removeNoneOrFirstOrSecond = areLinesTooSimilar(entry, otherEntry);
                        if (removeNoneOrFirstOrSecond != null) {

                            if (!removeNoneOrFirstOrSecond) {
                                final String removed = tokens.remove(i);
                                //                                System.err.println("\nREMOVED: " + removed + "\nKEPT   : " + otherEntry); // because was better or equal
                            } else {
                                final String removed = tokens.remove(ii);
                                //                                System.err.println("\nREMOVED: " + removed + "\nKEPT   : " + entry); // because was better or equal
                            }
                            break; // IMPORTANT!
                        }

                    }
                }
            }


            this.tokens = Collections.unmodifiableList(tokens);

        }


        public String toString() {

            final StringBuilder sb = new StringBuilder();
            for (String token : tokens) {
                sb.append(token).append('\n');
            }
            return sb.toString();
        }


    }


    /**
     * Do NOT call with NULL/EMPTY arguments.
     *
     * @return NULL if not too similar. False if the FIRST seems superfluous. True if the SECOND seems superfluous.
     */
    private static Boolean areLinesTooSimilar(final String line1,
                                              final String line2) {

        final int l1 = line1.length();
        final int l2 = line2.length();

        final double lenDiffRatio = Math.min(l1, l2) / (double) Math.max(l1, l2); // Results in 1 or less.

        if (lenDiffRatio >= MIN_LENGTH_DIFFERENCE_RATIO) {

            if (l2 < l1) {
                // Compare the other way round.
                if (line1.contains(line2)) {
                    return false;
                }
            } else {
                if (line2.contains(line1)) {
                    return true;
                }
            }

        }

        return null;
    }


    private static List<DumbTokenList> doTheInsaneParsingThing(final File file) {

        final List<DumbTokenList> ret = new ArrayList<>();

        final StringBuilder sb = new StringBuilder();
        try (final InputStream is = new BufferedInputStream(new FileInputStream(file))) {

            final int bufMinus1 = 4;
            final Charset charset = Charset.forName("Cp1252"); // =ansi

            final int[] buf = new int[bufMinus1 + 1]; // "DATA"
            //            while ((buf[buf.length - 1] = is.read()) >= 0) {
            while (true) {

                buf[bufMinus1] = is.read();

                if (buf[bufMinus1] < 0 || (
                        buf[0] == 'D' &&
                                buf[1] == 'A' &&
                                buf[2] == 'T' &&
                                buf[3] == 'A' &&
                                buf[4] == ':')) {

                    if (sb.length() > 0) {
                        ret.add(new DumbTokenList(sb.toString()));
                        sb.setLength(0);
                    }

                    if (buf[bufMinus1] < 0) {
                        break;
                    }

                } else {

                    sb.append(new String(new byte[] { (byte) buf[bufMinus1] }, charset));
                    //                    sb.append((char) buf[bufMinus1]);
                }


                // Shift minibuffer to front.
                for (int i = 0; i < bufMinus1; i++) {
                    buf[i] = buf[i + 1];
                }
            }


        } catch (IOException e) {
            e.printStackTrace();
        }


        // DEDUPLICATE DTLs
        for (int i = ret.size() - 1; i > 0; i--) {

            if (i < ret.size()) {
                final DumbTokenList dtlThis = ret.get(i);
                final int dtlThisTokenCount = dtlThis.tokens.size();

                for (int ii = i - 1; ii >= 0; ii--) {
                    final DumbTokenList dtlThat = ret.get(ii);
                    final int dtlThatTokenCount = dtlThat.tokens.size();


                    int scoreViaRemainingLines_this = dtlThisTokenCount;
                    int scoreViaRemainingLines_that = dtlThatTokenCount;


                    for (int o = 0; o < dtlThisTokenCount; o++) {
                        final String tokenThis = dtlThis.tokens.get(o);
                        for (int oo = 0; oo < dtlThatTokenCount; oo++) {
                            final String tokenThat = dtlThat.tokens.get(oo);

                            final Boolean tooSimilar = areLinesTooSimilar(tokenThis, tokenThat);
                            if (tooSimilar != null) {
                                scoreViaRemainingLines_this--;
                                scoreViaRemainingLines_that--;
                                break;
                            }

                        }
                    }

                    if (scoreViaRemainingLines_this < 0 || scoreViaRemainingLines_that < 0) {
                        throw new Error();
                    }

                    final double scoreActual_this = scoreViaRemainingLines_this / (double) dtlThisTokenCount;
                    final double scoreActual_that = scoreViaRemainingLines_that / (double) dtlThatTokenCount;


                    if (scoreViaRemainingLines_this < scoreViaRemainingLines_that) {
                        if (scoreActual_this < MIN_REMAININGLINES_PERCENTAGEOF_ALLLINES) {
                            final DumbTokenList removed = ret.remove(i);
                            //                            System.err.println("\nREMOVED:\n" + removed + "\nKEPT   :\n" + dtlThat);
                            break; // IMPORTANT.
                        }
                    } else {
                        if (scoreActual_that < MIN_REMAININGLINES_PERCENTAGEOF_ALLLINES) {
                            final DumbTokenList removed = ret.remove(ii);
                            //                            System.err.println("\nREMOVED:\n" + removed + "\nKEPT   :\n" + dtlThis);
                            break; // IMPORTANT.
                        }
                    }


                }

            }
        }

        return ret;
    }


}

1
Щоб запустити це, я використав наступні команди, javac "C:\Users\MLM\Downloads\CrappyChromeNotificationHistoryReader.java"(для компіляції), java -cp C:\Users\MLM\Downloads CrappyChromeNotificationHistoryReader(для запуску) Сценарій не вдався, if (scoreViaRemainingLines_this < 0 || scoreViaRemainingLines_that < 0) {тому я прокоментував увесь синтаксичний розбір doTheInsaneParsingThingі просто роздрукував усе, System.out.println(sb.toString());коли маркер додається до списку. Схоже, що "Сповіщення про платформу" обробляє лише робочі повідомлення сервера.
MLM

@MLM: Дякую за інформацію про javac. Щодо проблеми: працює для мене, якщо я вставляю джерело у відкритий проект Java 8 IntelliJ, вводите своє ім’я користувача (змінна "файл") та запускайте код.
Президент Dreamspace
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.