Есть ли способ просмотреть историю уведомлений браузера Chrome?


57

Я получаю уведомления 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, все готово. Наслаждайтесь!

РЕДАКТИРОВАТЬ:

  • Возможно, вам больше не нужно делать вышеуказанное.

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


2
Это не отвечает на вопрос просмотра истории уведомлений, просто просмотр уведомлений.
Бьорн

6
@BjornTipling Это действительно отвечает на это. Он спрашивает, может ли он увидеть уведомления, которые он пропустил в то время как далеко, и мой метод делает именно это.
Эсдрас Лопес

1
Если вы разместите ссылки в качестве комментариев, я добавлю их в ваш пост для вас, @EsdrasLopez
user418150

1
@ user418150 Я ценю это, но теперь я приобрел репутацию. :) Проверьте правки.
Эсдрас Лопес

2
Основная проблема здесь заключается в том, что он сохраняет уведомление, только если вы не нажмете на него. Несколько раз я нажимал на интересный заголовок статьи, но его не удалось загрузить, однако он все равно был удален из списка уведомлений. Обычно статьи слишком новы, чтобы их можно было гуглить, и часто заголовок уведомления не совпадает с заголовком статьи, поэтому он теряется в недрах сети.
Иборг

13

В 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 элементов из этого журнала. Затем вы можете открыть настройки Chrome и отключить это уведомление веб-сайта.

Обратите внимание, что если у вас есть несколько профилей в Chrome, ваш путь может быть другим, например так (Profile1 вместо Default):

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

3
Это должен быть принятый ответ. :)
Коди А. Рэй

1
Все еще работает в 2019 году (хотя журнал требует небольшой интерпретации). Отличный ответ спасибо
carpii

12

Если вы идете в %LocalAppData%\Google\Chrome\User Data\Default\Platform Notifications, есть файл журнала прошлых уведомлений.


4
хорошо, но рассмотрите возможность указания пути как "% LocalAppData% \ Google \ Chrome \ User Data \ Default \ Уведомления платформы" вместо жесткого кода. Отлично работает на любом ПК.
Дмитрий Гусаров

В папке UserData /-вам, возможно, придется сначала найти папку своего профиля, например «C: \ Users \ имя пользователя \ AppData \ Local \ Google \ Chrome \ UserData \ Profile 1 \ Уведомления платформы»
Maffelu

1
Эти данные являются двоичными. Как это читать?
Гея

На Chrome 71 и файл журнала пуст. Это было отключено в какой-то момент?
Джеймс

3
@ Gaia Я удивился тому же самому и просто взялся за какой-то дерьмовый код Java, который делает приемлемую работу по расшифровке большей части его. Я разместил это ниже: superuser.com/a/1410742/778383
Президент Dreamspace

3

Поскольку кажется, что невозможно получить запись уведомлений напрямую, если бы у меня была такая же проблема, я бы обманул, используя эмулятор телефона Android или телефон, как пользователь, который рекомендовал Pushbullet. Но есть не только Pushbullet, но и множество других приложений, мы могли бы обсудить приемы Android для прослушивания и записи уведомлений в отдельной теме.

Если вы программист, вы можете решить свою проблему с помощью самодельного расширения:

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

«Вы можете подключить функцию webkitNotifications.createNotification, чтобы при создании уведомления вы запускали какой-то определенный код».


2

Прикосновение к чему-то, что было упомянуто чуть выше, но с изюминкой, которая гарантирует, что вы не пропустите уведомление на OSX:

  1. На правой стороне главной верхней панели щелкните значок уведомления.

  2. Нажмите на зубчатое колесо (в правом нижнем углу экрана уведомлений)

  3. Выберите Chrome, чтобы настроить отображение уведомлений.

  4. По умолчанию выбраны «Баннеры», и они могут исчезать автоматически. Вместо этого выберите тип «Оповещение», и они останутся там, пока вы их не подтвердите!

Добро пожаловать :)


2

Вы можете увидеть историю Push-уведомлений. В самом нижнем правом углу экрана вашего ПК на панели задач находится нечто похожее на речевой пузырь, и если вы наведете на него курсор, вы увидите, что это на самом деле называется «уведомления». Если вы нажмете на этот пузырь, он покажет ваши непрочитанные / новые электронные письма и любые push-уведомления, которые вы не отклонили. Я пришел сюда в поисках этого ответа и не нашел его, но затем сумел решить это. Я использую Windows 10.


Да, это недавняя вещь на Win10, но это возможный ответ для Windows.
парадроид

-1

Кажется, что Pushbullet может решить вашу проблему. Они утверждают, что вы можете видеть ваши пропущенные уведомления, используя их расширение Chrome.

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


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

Эй, мило. Я попробую это. Я фактически уже использую Pushbullet, но не знал об этом расширении Chrome.
парадоид

Не могу найти эту функцию. Уведомление выскочило, и в истории уведомления его нет.
MadProps

Я переосмыслил вопрос, и подвох в этом. Если ваш телефон получает уведомление, pushbullet доставит его на ваш рабочий стол и сообщит, что у вас есть непрочитанные уведомления (возможно, вы видели его на своем телефоне или что у вас есть). Для каких сайтов вы получаете уведомления Chrome? Если есть приложение для него, вы всегда можете установить его, и тогда вы получите уведомления от pushbullet на свой рабочий стол / ноутбук / что угодно.
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

Java-код, достойный распятия:

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());когда токен был добавлен в список. Похоже, «Уведомления платформы» обрабатывают только push-уведомления работника сервера.
MLM

@MLM: Спасибо за информацию о Javac. Что касается проблемы: у меня работает, если я вставляю исходный код в открытый проект Java 8 IntelliJ, вставляю свое имя пользователя (переменная «file») и запускаю код.
Президент Dreamspace
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.