Полезная информация

Будьте в курсе последних изменений в мире Mozilla, следя за нашим микроблогом в Twitter.

№117-02-2025 22:32:26

yup
Участник
 
Группа: Members
Зарегистрирован: 15-04-2016
Сообщений: 1122
UA: Seamonkey 2.49

Странные записи в places.sqlite

Люди добрые, подскажите, кто знает.

Решил я немного повысить функциональность окна истории посещений и в процессе своих ковыряний обнаружил в places.sqlite в таблице moz_places странные записи. У них в поле last_visit_date стоит совершенно нормальная (и даже правдоподобная) дата, но при этом в поле visit_count стоит 0.
И таких записей у меня там нашлось аж три десятка.

Потом уже, глядя на URL-ы в этих записях, я выяснил, что и браузер в своём окне истории их показывает. И если столбец "Число посещений" сделать видимым, то оказывается, что у всех прочих записей там стоит число, а у этих - пустое место.

Вопрос: Является ли наличие подобных записей нормальным или это последствия каких-то сбоев в работе с БД? И если это нормально, то как подобные записи образуются?

Отсутствует

 

№218-02-2025 07:38:04

_zt
Участник
 
Группа: Members
Зарегистрирован: 10-11-2014
Сообщений: 1685
UA: Firefox 128.0

Re: Странные записи в places.sqlite

yup
Возможно эти закладки созданы перетягиванием грязных ссылок на панель? А при открытии ссылка чистится чем-то и в итоге количество "visit_count стоит". Или наоборот.

Отсутствует

 

№318-02-2025 11:23:07

yup
Участник
 
Группа: Members
Зарегистрирован: 15-04-2016
Сообщений: 1122
UA: Seamonkey 2.49

Re: Странные записи в places.sqlite

Нет, я не с закладками разбираюсь, а с историей посещений.

Понятно, что таблица moz_places общая для всего, но те ссылки я никогда в закладки не помещал. Это совершенно точно.

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

Отсутствует

 

№418-02-2025 12:35:45

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2309
UA: Firefox 78.0

Re: Странные записи в places.sqlite

yup пишет

Вопрос: Является ли наличие подобных записей нормальным

Ну, раз загрузки могут образовывать подобные записи,
то, как минимум, их наличие нельзя назвать совсем уж не нормальным.

Отсутствует

 

№518-02-2025 14:01:37

_zt
Участник
 
Группа: Members
Зарегистрирован: 10-11-2014
Сообщений: 1685
UA: Firefox 128.0

Re: Странные записи в places.sqlite

yup
Точно, чего то я тупанул с утра пораньше. Тогда возможно рефереры, ну типа переходишь по ссылке, а там перенаправление.

Отсутствует

 

№618-02-2025 15:10:39

yup
Участник
 
Группа: Members
Зарегистрирован: 15-04-2016
Сообщений: 1122
UA: Seamonkey 2.49

Re: Странные записи в places.sqlite

Dumby пишет

Ну, раз загрузки могут образовывать подобные записи

А вот это вопрос интересный. У меня же Iceape (Seamonkey), а там загрузки лежат в отдельном файле - downloads.sqlite. И счётчика посещений у них нет.


Но для нулевого счётчика у Firefox-овых загрузок хотя бы смысл и механизм понятен - они в historyvisits не пишутся, и frecency для них считать незачем. А тут посещения...


_zt пишет

Тогда возможно рефереры, ну типа переходишь по ссылке, а там перенаправление.

Я вчера вечером выделил время и заново посетил все эти ссылки. Нет, всё честно, никаких перенаправлений. Максимум, "Домен не существует" или "Страница не существует". Но раз в places.sqlite у них записан title, то значит тогда по этому адресу открылась именно страница.


Да, и ещё один нюанс: у Seamonkey, в отличие от Firefox, те URL-ы, которые ответили перенаправлением, в базу данных вообще не попадают.


Поэтому текущая (сомнительная) гипотеза такая: браузер перед зависанием успел внести запись в moz_places, но не успел в moz_historyvisits. А потом какой-то внутренний процесс (возможно, подсчёт frecency) пересчитал записи в historyvisits и внёс актуальное значение (ноль) в moz_places.


Dumby

Моя затея с расширением для улучшения окна истории оказалась несколько сложнее, чем представлялось изначально. Похоже, что слишком много собственного кода браузера придётся подменять своим.

Если самому с чем-то справиться не удастся, можно за помощью обратиться? Осталось ещё что-то в памяти о XUL-расширениях?

Отредактировано yup (18-02-2025 15:25:07)

Отсутствует

 

№718-02-2025 17:29:55

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2309
UA: Firefox 78.0

Re: Странные записи в places.sqlite

yup пишет

Если самому с чем-то справиться не удастся, можно за помощью обратиться?

Обратиться-то можно, но будет ли от этого толк?
Плюс, надо ссылку на этот, такой же как у тебя, Iceape.
Даже если скачается и встанет, то он будет у меня в оффлайн-среде.
Но тогда, хотя бы будет предмет для обсуждения.

XUL-расширениях

Нет такого понятия.


Были оверлейные расширения.
Ещё, были расширения системы «Афёра SDK».


Были и есть bootstrapped расширения.
Сейчас, в Firefox, есть ещё странная разновидность
расширений, именуемая WebExtensions Experiments.

Отсутствует

 

№818-02-2025 19:55:36

yup
Участник
 
Группа: Members
Зарегистрирован: 15-04-2016
Сообщений: 1122
UA: Seamonkey 2.49

Re: Странные записи в places.sqlite

Dumby пишет

Обратиться-то можно, но будет ли от этого толк?

Вот я и спросил - будет ли?
Я в разные периоды своей жизни разными делами занимался, от многих из них в голове только смутные воспоминания остались.


Dumby пишет

Плюс, надо ссылку на этот, такой же как у тебя, Iceape.

Не обязательно. Я под него перенёс с полсотни расширений и кнопок CustomButtons от Seamonkey. Процентов 80 из них не потребовали вообще никаких изменений, только новый ID в install.rdf записать. А у большинства из оставшихся 20% - этот же ID добавить в chrome.manifest.
То есть, совместимость с SM 2.49 очень высокая. (Я для Iceape и всех остальных основанных на UXP программ DOM Inspector адаптировал и ещё кучку исследовательских расширений, поэтому потроха изучил основательно.)
И обновления браузера (а они довольно часто выходят) ни разу ничего не поломали.


А сама программа берётся здесь: https://o.rthost.win/hbl-uxp/index.php? … &order=asc


Dumby пишет

Даже если скачается и встанет, то он будет у меня в оффлайн-среде.

Ну так для работы с историей доступ к Интернету не требуется. Я даже places.sqlite подкину, если что. Хотя там вопросы предвидятся типа: "Как вот из этого места кода достучаться до вон той функции?"


Dumby пишет

Нет такого понятия.

Официально нет.


Потому что сначала только такие и были. Потом появились другие - им названия дали, чтобы отличать. А этим так и не удосужились.


А как-то же сейчас называть надо. "Оверлейные расширения" тоже ведь не совсем официальное название. Поэтому приходится между собой договариваться. Каждому микросообществу в отдельности.


Dumby пишет

Были и есть bootstrapped расширения.
Сейчас, в Firefox, есть ещё странная разновидность расширений, именуемая WebExtensions Experiments.

А разве bootstrapped в нынешнем FF поддерживаются? Я думал, от всего "проклятого прошлого" давно отреклись в угоду WebExtensions.

Отредактировано yup (18-02-2025 20:00:01)

Отсутствует

 

№918-02-2025 21:00:45

T0PMØ3iLLA
Участник
 
Группа: Members
Зарегистрирован: 18-09-2017
Сообщений: 21
UA: Firefox 91.0

Re: Странные записи в places.sqlite

Скажу более… настройки — Cookies — Управление данными…
В этом окне можно увидеть "кол-во Cookies" = 0, однако РАЗМЕР может доходить в несколько МЕГАБАЙТ!

Отсутствует

 

№1018-02-2025 21:16:08

yup
Участник
 
Группа: Members
Зарегистрирован: 15-04-2016
Сообщений: 1122
UA: Seamonkey 2.49

Re: Странные записи в places.sqlite

T0PMØ3iLLA
Они ж в SQL-ной базе данных хранятся. А это как MFT у NTFS: когда много записей добавляется - растёт; когда записи удаляются - не уменьшается.


Операция уменьшения ("vacuum") в браузере есть, но, по-моему, она там только вручную запускается.
Впрочем, браузеров развелось много разных, за всеми не уследишь.


Ну, и минимальный размер у некоторых из этих файлов совсем не маленький. Даже у абсолютно пустых, свежесозданных.


(У меня всю жизнь в настройках политика обращения с куками - "удалять по завершении сеанса". А у файла cookies.sqlite размер сейчас полмегабайта. Но это же не значит, что в нём столько хранится. С точки зрения движка SQLite он практически пустой.)

Отредактировано yup (18-02-2025 21:22:47)

Отсутствует

 

№1118-02-2025 23:57:06

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2309
UA: Firefox 78.0

Re: Странные записи в places.sqlite

yup пишет

Вот я и спросил - будет ли?

Откуда же мне знать не видя вопроса, тут не угадаешь.

программа берётся здесь

Фух, скачал 52.9.20250206, развернул, запихал CB и DOMi, можно смотреть.


Так вот, система-то оффлайн, но есть прога Wampserver,
в которой я совсем ничего не понимаю,
но могу HTML'ки на диске размещать так,
что браузер отображает их как настоящие http-страницы.


Открываю вкладку, набираю адрес, страница открывается.
В базе: last_visit_date — есть, visit_count — единица.


Теперь, Ctrl+H, ПКМ —> «Delete»
В базе: запись просто исчезает. Из окна «History» тоже.


Теперь, ПКМ по этой странице —> «Save Page As…», сохраняю.
И вот оно!
В базе: last_visit_date — есть, visit_count — ноль.
И в окне «History» строка есть. С пустой графой «Visit Count».


Кстати, на странице есть ссылка.
Если ПКМ по по ней —> «Save Link Target As…»,
то снова получается подобная запись.


Это я не к тому, что у тебя они именно так и образовались,
а к тому, что такое возможно в принципе, и без каких-либо сбоев.

А как-то же сейчас называть надо.

Да, ты всё верно говоришь.
Просто название «XUL-расширение» какое-то дурацкое.


Если имеется в виду как разновидность расширения,
то не подходит, поскольку можно представить
оверлейное расширение вообще без XUL'а,
и bootstrap расширение, которое навалит целый вагон XUL'а.


А если имеется в виду как противопоставление WebExtensions,
тогда избыточно, поскольку WE расширениями не являются.
Это совершенно отдельный вид дополнений,
а официально такими именуются лишь в пропагандистских целях.
То есть, либо WebExtensions, либо просто «расширение».


Ну, таково моё мнение, которое, впрочем, да и вообще, не важно.

А разве bootstrapped в нынешнем FF поддерживаются?

Конечно нет. И уже давно. Но засунуть можно.
Самих расширений, наверно, немного, но они существуют.

Отсутствует

 

№1219-02-2025 01:15:18

yup
Участник
 
Группа: Members
Зарегистрирован: 15-04-2016
Сообщений: 1122
UA: Seamonkey 2.49

Re: Странные записи в places.sqlite

Dumby пишет

Откуда же мне знать не видя вопроса, тут не угадаешь.

А я напишу. Всю историю - от первоначальной задумки до той ситуации, до которой я сейчас "докатился". Но чуть позже - чтобы это отдельным сообщением было.


Dumby пишет

Теперь, ПКМ по этой странице —> «Save Page As…», сохраняю.
И вот оно!
В базе: last_visit_date — есть, visit_count — ноль.

Да уж... Ну и где логика (разработчиков)? (На всякий случай: это я сейчас в Iceape сижу, но используемый places.sqlite унаследован от Seamonkey, и записи в нём копились лет 20. А эти "обнулённые" и очень старые нашлись, и совсем свежие, буквально позавчерашние.)


Dumby пишет

Кстати, на странице есть ссылка.
Если ПКМ по по ней —> «Save Link Target As…», то снова получается подобная запись.

Ну ладно, это ещё как-то понять можно - фактически страницу не посещали.
Но сбрасывать в 0 счётчик при сохранении в файл текущей страницы???


Но теперь мне надо эту новость обдумать и поизучать ситуацию самому.


А пока объясню, почему возник интерес к этим нулям.


Я пока пришёл к тому, что для реализации моей идеи придётся самому формировать SQL-ный запрос к БД и самому заполнять окно истории. А выяснить, какой запрос туда уходит от штатного кода, не удалось. Пришлось экспериментировать. Первый заезд был с очевидным условием: visit_count > 0. Записей вернулось в несколько раз больше, чем показывает окно истории.


Посмотрел на эти записи, увидел, что у многих стоит hidden = 1. Что это hidden означает, не знаю, но добавил в запрос NOT hidden. Получил чуть-чуть меньше записей, чем в окне истории.


Тогда просто сохранил в один текстовый файл URL-ы из моего запроса, в другой - URL-ы из окна истории, и сравнил их. А потом нашёл в БД эти записи и прикинул, чем они отличаются от "нормальных", после чего заменил visit_count > 0 на last_visit_date <> 0. В результате, наконец, получил точное совпадение.


Всё. В том смысле, что к этим нулям я прицепился только из дотошности - хочу, чтобы показываемая моим кодом история содержала ровно те же записи, что и в штатном случае.
А к главным проблемам всё это отношения не имеет.


Dumby пишет

Да, ты всё верно говоришь.
Просто название «XUL-расширение» какое-то дурацкое.

Но тут такая ситуация:


1. Название "оверлейные расширения" ссылается на те же самые XUL overlays, что и название "XUL-расширения".


2. Я "за рулём" компьютеров с 70-х годов. И тогда, и в 80-е, и в начале 90-х в программировании широко использовались термины "оверлеи" и "оверлейные программы". Причём эти понятия не имели никакого отношения к UI, а описывали особенности внутреннего устройства самих программ.
И сидит во мне это настолько крепко, что даже сейчас назвать мозилловские расширения оверлейными у меня "язык не поднимается".


Dumby пишет

Если имеется в виду как разновидность расширения, то не подходит, поскольку можно представить оверлейное расширение вообще без XUL'а

Разве? По-моему, как минимум один файл .XUL должен быть, пусть даже и не меняющий ничего во внешнем виде. Иначе как код расширения запускаться будет?
(Вариант, когда в расширении только новая служба имеется, рассматривать не будем - слишком уж экзотический случай.)

Отредактировано yup (19-02-2025 01:26:10)

Отсутствует

 

№1319-02-2025 21:34:47

T0PMØ3iLLA
Участник
 
Группа: Members
Зарегистрирован: 18-09-2017
Сообщений: 21
UA: Firefox 91.0

Re: Странные записи в places.sqlite

Я про размер не самого файла базы данных, а конкретно про столбец Storage в окне Firefox (как со столбцом кол-ва посещений у истории) — тоже пишет в мегабайтах, хотя у столбца “Cookies” слева показывает значение 0:

Выделить код

Код:

data:image/png;base64,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

Кусты реестра SOFTWARE тоже у мн. пользователей за полсотню метров "растягивались" из-за каких-то несчастных пары значений в Microsoft\Windows NT\CurrentVersion\Perflib\CurrentLanguage (ошибка загрузки счётчиков в perfmon.msc), занявших десятки мегабайт — lodctr /r хоть и исправило данные (соответственно, размер там стал куда более адекватным), но сам куст SOFTWARE так и остался за полсотню метров… А использовать "оптимизаторы реестра" опасно, т.к. фрагментироваться новые данные станут сильнее — знать бы, как это всё перераспределить (дефрагментировать) вручную, оставив ещё разряжённые участки между определёнными подразделами…
А про NTFS… ну… моё мнение по этому поводу уж слишком оффтопное выходит

скрытый текст
не совсем уж и проблема, если есть куда перекинуть все данные, знать бы, как вместе с жёсткими и символическими ссылками переместить (и то, если нигде не использовался \\?\Volume{guid}\ конкретно на этот + хорошо бы как с robocopy /COPY:DATSO, /DCOPY:T, хотя, права доступа тоже "от корня" надо соответствующим образом задать заранее, а то этот robocopy сохраняет не «то наследование», которое нужно было) а там потом тупо пересоздать ещё раз тот же раздел с гораздо меньшим размером, затем расширить! Затем с резервного вернуть обратно (с теми же жёсткими и символьными ссылками), и глянуть, насколько в этот раз MFT расширило… Правда, у одного моего 1-терабайтного hdd банальное СОЗДАНИЕ какого-либо раздела внутри расширенного приводит к удалению трёх других, так же располагающихся в расширенном (хотя в нём же и ещё два других находятся, но те при каждой такой попытке остаются на месте)! Причём повторяется у меня такое и на 7-ке, и на 8.1 Embedded, и на 20H2! Только благодаря установщику WinXP получается их ещё раз создавать — вот тут уже либо мне придётся расширить те "неубиваемые" два раздела внутри расширенного до их пределов, либо переносить на третий hdd, сносить всё, да по-новой "шинковать", отказавшись на этот раз от этого глючного ResierFS, из-за которого, скорее всего, винда и не может адекватно определить, где же на самом деле начинается расширенный раздел: в diskmgmt.msc: только с третьего (после него ещё последним идёт primary), т.е. после незанятого пространства первые два определяет как primary, а в diskpart: сразу после пустого незанятого 16МБ пространства первый считает расширенным, т.е. все = logical, и только последний primary! И всё бы ничего, если бы и diskart тоже не повисал бы при попытке создать раздел в той части диска… тут похоже только "хирургическим" путём нужно как-то чинить таблицу разделов…

Отредактировано T0PMØ3iLLA (19-02-2025 21:56:59)

Отсутствует

 

№1419-02-2025 23:57:05

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2309
UA: Firefox 78.0

Re: Странные записи в places.sqlite

T0PMØ3iLLA пишет

конкретно про столбец Storage в окне Firefox (как со столбцом кол-ва посещений у истории) — тоже пишет в мегабайтах, хотя у столбца “Cookies” слева показывает значение 0

Что ещё за «хотя»?


Столбец «Cookies» — это количество кук.
Столбец «Storage» — это что-то типа попытки подсчёта добра, которое видно по Shift+F9


Оконце ведь называется «Manage Cookies and Site Data»,
а не просто «Manage Cookies».

Отсутствует

 

№1522-02-2025 03:03:24

yup
Участник
 
Группа: Members
Зарегистрирован: 15-04-2016
Сообщений: 1122
UA: Seamonkey 2.49

Re: Странные записи в places.sqlite

Ну вот, собрался с силами и попытаюсь описать, в чём состояла затея и до чего я докатился.

Есть у браузера один недостаток, который много лет не даёт мне радоваться жизни.
Когда я смотрю на окно закладок, я для каждой записи сразу вижу, есть ли в истории посещений отметка, что я там был, и дату посещения.


А обратное, увы, невозможно: когда я смотрю на любую запись в окне истории, я никак не могу определить, есть ли у меня закладка с таким URL или нет.
И даже пункт меню "Добавить в закладки" активен в том числе и на URL-ах, которые в закладках уже есть, и не моргнув глазом даёт возможность добавить их туда ещё раз.

Вот это безобразие и хочется устранить.

Да чего там делать-то?
Желание же самое простое: добавить в таблицу, где история отображается, ещё один столбец, в котором как-нибудь (да хоть просто плюсиком) будет обозначаться наличие посещённой страницы в закладках.


И реализация представлялась несложной. Есть XUL окна (chrome://communicator/content/history/history.xul) с этой таблицей, программно добавляем в эту таблицу новый столбец.
Находим функцию, которая получает из базы данных записи для этой таблицы, смотрим запрос, создаём свой модифицированный вариант и изыскиваем способ подменить или запрос, или функцию.


Невыносимая сложность простоты
Трудность внезапно всплыла с запросом. Оказалась, что его просто-напросто нет. Функция, которая получает данные для таблицы, запроса сама не формирует, а нижележащим функциям передаёт в качестве параметра пустую строку (или не пустую, но тогда это то, что в окне истории набрано в строке поиска).


А нижележащие функции, которые вызываются, это History API, в котором нет ничего в данном случае полезного. Там можно управлять перечнем запрашиваемых полей, но выбор только из жёстко заданного набора, в котором ничего подходящего для меня нет.


Всё ниже, и ниже, и ниже
Но History API это всего лишь надстройка над Places API.


Сначала Places API обнадёжило: оказалось, что у каждом возвращаемой записи истории есть поле bookmarkIndex. Я обрадовался, решив, что это индекс в таблице moz_bookmarks, и значит, если у записи там стоит осмысленное число, то закладка есть. Но эксперимент показал, что для всех записей из моей истории там возвращается -1, хотя многие из них в закладках точно имеются.


А критический взгляд на описание этого поля в документации показал, что описание это неоднозначное, и прочитать его можно по-разному - в зависимости от того, как хочешь его прочитать.


Затем из документации выяснил, что поле itemId у результатов это тоже индекс в закладках. Правда, для моих записей в нём тоже всегда -1 стоит. И да, его описание тоже можно прочитать по-разному, было бы желание.


Прошёл отладчиком дальше (в смысле - ниже) и добрался в конце концов до вызова Сишной функции, но формирования запроса, который можно было бы модифицировать, так и не встретил.
Значит, он где-то в Сишном коде, а его своим расширением не подменишь.


Мы пойдём другим путём
Параллельно с попытками что-то сделать через высокоуровневое API я рассматривал вариант полностью самому задать SQL-ный запрос, напрямую отправить его в БД, и потом скормить таблице полученный результат.


Сначала подобрал запрос к moz_places, дающий такой же результат, как и штатный код (именно тогда и возник вопрос о нулях).
Потом добавил к запросу заглядывание в таблицу moz_bookmarks. Результат получился правильным.
А потом обнаружил, что привлекать moz_bookmarks не требуется, потому что поле foreign_count в записях moz_places это счётчик, указывающий, сколько раз URL из записи встречается в закладках.
То есть, так получается не только быстрее, но даже и круче, чем хотелось изначально - перед глазами будет не просто плюсик, а счётчик.


Что дальше, Дава?
И теперь я не могу решить, куда дальше двигать.


Для ковыряния в истории SQL-запросами в Places API есть парочка функций, унаследованных от Storage API:

  1. executeStep(). Возвращает по одной записи за раз. Чтобы получить все записи, её нужно вызывать в цикле до упора. А функция синхронная, пока цикл будет крутиться, весь браузер будет стоять.
  2. executeAsync(). Возвращает (в моём эксперименте) примерно 15 записей за раз. То есть, её тоже нужно крутить в цикле, но, по крайней мере, браузер не заклинит. Зато есть опасение, что таблица на глазах у пользователя будет заполняться рывками. Чтобы этого избежать, придётся куда-то перекладывать полученные порции данных, и только после полного получения всего приступать к заполнению таблицы.

А последнее предложение в п.2 неплохо сочетается с двумя нюансами, которые тоже хочется использовать:

  1. Содержимое окна истории динамическое - оно меняется, когда пользователь, держа окно открытым, посещает новые страницы, и в некоторых других случаях. Для этого окно обвешано кучей разных наблюдателей. Если я буду заполнять окно самостоятельно, некоторая их часть не сможет работать, и придётся заменять своим кодом ещё и их, а хочется сохранить всё по-максимуму.
  2. Сейчас заполнение таблицы реализовано элементарно просто (см. функцию load() в chrome://communicator/content/history/tree.xml).

Очень хочется преобразовать то, что возвращает executeAsync(), в то, что можно скормить PlacesTreeView внутри load(), и таким образом обойтись только навешиванием своей простейшей надстройки над getCellText() из chrome://communicator/content/history/treeView.js


Вот над этим сейчас голову и ломаю (по мере наличия времени).


А всё так хорошо начиналось...

Отредактировано yup (22-02-2025 03:08:01)

Отсутствует

 

№1623-02-2025 02:27:49

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2309
UA: Firefox 78.0

Re: Странные записи в places.sqlite

yup
Какое восхитительное описание! Доходчиво и подробно.
Даже слишком, не уверен, что я смогу прямо сходу это дочитать.
Но прокомментирую.

Желание же самое простое: добавить в таблицу, где история отображается, ещё один столбец, в котором как-нибудь (да хоть просто плюсиком) будет обозначаться наличие посещённой страницы в закладках.
И реализация представлялась несложной.
Трудность внезапно всплыла с запросом.

Странные у тебя понятия о простом и сложном.


И вообще, тут как бы ожидался, собственно, код, добавляющий столбец.
Полная версия реализации. Если расширением, значит в base64 или https://www.upload.ee
(ну, знаешь, типа «нет кода — нет разговора»).


В столбце — что угодно, например, случайное число.
В коде — коммент-слот а-ля «// Здесь надо получить текст столбца».


Ладно, для начала, рассмотри вариант.
В базу не полезу, если не убедишь в необходимости.
Чесать репу над колонкой не буду, в надежде, что у тебя есть готовый код.


Вот демо-набросок.
Открываем вкладку с адресом chrome://communicator/content/history/history.xul
На ней, вызываем веб-консоль (Ctrl+Shift+K).
С js-терминала консоли запускаем код.


Ожидаемый результат: в колонке «Location»
урлы, имеющиеся в закладках, будут красным болдом.


Ну, это если у тебя никакой сторонний код не претендует на переопределение
PlacesTreeView.prototype.getCellProperties(), иначе возможен конфликт.

скрытый текст

Выделить код

Код:

(() => {

	// Shortcuts
	var bkd = "bookmarked";
	var uri = Services.io.newURI;
	var bms = PlacesUtils.bookmarks;
	var rtu = Components.interfaces.nsINavHistoryResultNode.RESULT_TYPE_URI;

	// CORE!
	var isb = bms.isBookmarked;

	// Redef getCellProperties()
	var proto = PlacesTreeView.prototype, {getCellProperties} = proto;
	proto.getCellProperties = function PTV_getCellProperties(aRow, aColumn) {

		if (aColumn.id == "URL") {
			var node = this._getNodeForRow(aRow);
			return node.type == rtu && isb(uri(node.uri)) ? bkd : "";
		}
		return getCellProperties.call(this, aRow, aColumn);
	}

	// Style
	var css = `
		treechildren::-moz-tree-cell-text(${bkd}) {
			color: red !important;
			font-weight: bold !important;
		}
	`.trim();
	document.firstChild.before(document.createProcessingInstruction(
		"xml-stylesheet", `href="data:text/css,${encodeURIComponent(css)}" type="text/css"`
	));

	// Def invalidate
	var inv = gHistoryTree.treeBoxObject.invalidate.bind(gHistoryTree.treeBoxObject);
	inv();// Apply immediately

	// Observer
	var obj = Object.create(null);
	obj.QueryInterface = XPCOMUtils.generateQI([Components.interfaces.nsINavBookmarkObserver]);
	var obs = new Proxy(obj, {get: (trg, name) => trg[name] || inv});

	bms.addObserver(obs, false);
	addEventListener("unload", () => bms.removeObserver(obs), {once: true});

})();

Отредактировано Dumby (23-02-2025 02:42:48)

Отсутствует

 

№1723-02-2025 17:33:52

yup
Участник
 
Группа: Members
Зарегистрирован: 15-04-2016
Сообщений: 1122
UA: Seamonkey 2.49

Re: Странные записи в places.sqlite

Dumby пишет

Странные у тебя понятия о простом и сложном.

Ну так:
Добавить столбец в окошко таблицы на экране - раз плюнуть.
Данные хранятся в файле .sqlite, значит добываются они оттуда с помощью SQL-запроса. Запрос, который будет возвращать нужные для нового столбца данные, сформировать тоже труда не составляет.


Таково было первоначальное представление - до того, как внутрь полез.


Dumby пишет

И вообще, тут как бы ожидался, собственно, код, добавляющий столбец.

Если нужно, код я изображу. Просто у меня есть изрядный опыт работы с элементом <tree>, и поэтому вопросов по визуальной части затеи не предвидится, все изыскания - как бы данные, получаемые из places, так оформить, чтобы их было удобно в этот элемент засунуть.


А несколько способов добавить столбец в таблицу вот (без оглядки на то, насколько тот или иной применим в данном случае):


1. У <tree> (таблицы) есть дочерний элемент <treecols> (шапка), а у <treecols> есть метод appendChild(), позволяющий добавлять в таблицу новые столбцы (<treecol>) и разделители между ними (<splitter>).


2. Таблица истории со всеми её столбцами описана в файле history.xul, который открывается по команде из меню. Расширение может заменить код этой команды на свой, который будет открывать другой .xul вместо штатного.


3. Элемент <tree> динамический. Если в нём уже есть какие-то строки и добавляется новая строка, имеющая поле, которого не было у предыдущих, то столбец для этого поля добавится автоматически.


В общем, как изменить внешний вид таблицы, вопросов нет и не предвидится. И вообще я пока вопроса никакого не задал, а просто обрисовал, что затеял и чем сейчас занимаюсь: перебираю варианты, которыми можно полученные результаты запроса подсунуть в качестве исходных данных для таблицы.


А эти результаты сами по себе штука занятная. Вот элементарный код:

Выделить код

Код:

var sql = 'SELECT * FROM moz_places';
var sql_stmt = Components.classes['@mozilla.org/browser/nav-history-service;1']
                         .getService(Components.interfaces.nsPIPlacesDatabase)
                         .DBConnection
                         .createStatement(sql);
sql_stmt.executeStep();
var resultRow = sql_stmt.row;
console.log(resultRow);
sql_stmt.reset();

Вот что получается в консоли:
Rj7Ka4DuMir0SAOJ2DeFRIH5LmwoQLwZHEzo6lUG.png


А теперь после console.log(resultRow) добавляю строки:

Выделить код

Код:

console.log(resultRow.id);
console.log(resultRow.url);
console.log(resultRow.hidden);

И вот что в консоли теперь:
0b97cmXIiDmMRhLbUEIIPMWFyfUACOx4eQ6ZRzmk.png
Смотрим на правую часть окна - какие там интересные значения у всего, и какие интересные изменения произошли в структуре объекта-результата. "А ведь ничего не сделал, только вошёл..."


Так что пока исследую штатный код, заполняющий таблицу и потом всячески с ней работающий, чтобы решить, что проще и безопаснее - преобразовать это чудо (StatementRow) в тот тип, с которым код работает сейчас, или заменить код своим, ориентированным именно на StatementRow.


Dumby пишет

это если у тебя никакой сторонний код не претендует на переопределение
PlacesTreeView.prototype.getCellProperties(), иначе возможен конфликт.

То, что существуют конфликтующие друг с другом расширения - не секрет. Но для окна расширений практически нет. А те, которые есть, либо совместимыми, скорее всего, окажутся, либо настолько несовместимы по назначению, что никто такую пару одновременно ставить не станет.


Добавлено 23-02-2025 17:53:00
А что касается "выделения красным" - я думал о чём-то подобном, но решил, что если интересующие строки предстоит в длинном списке выискивать глазами, то пометки, стоящие в отдельном столбце, высматривать будет легче. А сейчас ещё и счётчик нашёл...

Плюс к тому, по столбцу и отсортировать можно.


Ну, и скорость. Это я историю по несколько раз в день чищу. А есть люди, которые годами этого не делают - принципиально. А тут для каждой записи отдельный запрос делается. В то время как всё сразу можно было бы получить одним запросом.


Попробую раздобыть чужой нечищенный places.sqlite - посмотрю, какая скорость получается.


Upd:
До полей с неизвестными заранее именам в результатах SQL-ного запроса добираются вот так:

Выделить код

Код:

var sql = 'SELECT * FROM moz_places';
var sql_stmt = Components.classes['@mozilla.org/browser/nav-history-service;1']
                         .getService(Components.interfaces.nsPIPlacesDatabase)
                         .DBConnection
                         .createStatement(sql);

var colCount = sql_stmt.columnCount;
var columnNames = Array(colCount);
for (var i = 0; i < colCount; i++) {
  columnNames[i] = sql_stmt.getColumnName(i);
}

sql_stmt.executeStep();
var resultRow = sql_stmt.row;
for (var i = 0; i < colCount; i++) {
  columnName = columnNames[i];
  console.log(columnName + ' = ' + resultRow[columnName]);
}
sql_stmt.finalize();

Теперь уже более-менее понятно, как это таблице подсовывать.
(Я ж почему к этим именам так прицепился: хотелось свой довесок сделать универсальным, чтобы мог работать с результатами любого запроса, а не только строго фиксированным набором полей, как в оригинале.)

Отредактировано yup (24-02-2025 01:27:29)

Отсутствует

 

№1824-02-2025 18:40:47

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2309
UA: Firefox 78.0

Re: Странные записи в places.sqlite

yup пишет

вопросов по визуальной части затеи не предвидится

Не, это я, скорее, к тому, чтобы мне взять
уже готовый код, а не сочинять самому.
Так же, даёт возможность проникнуться концепцией в целом.

Вот что получается в консоли

Да, вижу. Действительно странно.

Ну, и скорость.
тут для каждой записи отдельный запрос делается. В то время как всё сразу было бы получить одним запросом.

Я тут попробовал сочинить тестовый код.
Ну, как смог, SQLite-то я не знаю.


Суть: получить объект, где свойства — урлы истории,
а значения — количество штук в закладках.
Ну и замерить сколько на это уйдёт времени.


Запускал на Firefox 56, places.sqlite — 65 мегабайт.
Находит где-то 69 тысяч урлов.
Выигрывает практически всегда TEST_SQL_AGG_NATIVE
а TEST_XPCOM всегда последний.


Кстати, наткнулся на такое:
Обнаружился один урл, для которого foreign_count
не совпадает с тем, что отдаёт TEST_XPCOM
В базе значение — три,
а кодом без использования чтения базы — два.


Оказалось, что добавление к закладке tag'а (метки)
увеличивает foreign_count на единицу.
Видимо, PlacesUtils.bookmarks.getBookmarkIdsForURI()
отдаёт результат без учёта папки меток.


А вот на Iceape — там для такой закладки совпадает,
то есть метки учитываются.
И ещё, у меня там чаще выигрывает TEST_SQL_WHILE_LOOP
наверно из-за мизерного размера базы.

скрытый текст

Выделить код

Код:

(() => {
	var ts = Components.utils.now;
	var conn = PlacesUtils.history.DBConnection;
	var from = " FROM moz_places WHERE hidden = 0 AND last_visit_date NOTNULL";

	var testFunctions = [

		function TEST_XPCOM() {
			var query = PlacesUtils.history.getNewQuery();
  			var options = PlacesUtils.history.getNewQueryOptions();
  			options.queryType = Components.interfaces.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY;
  
  			var u = Services.io.newURI;
  			var bids = PlacesUtils.bookmarks.getBookmarkIdsForURI;
  
  			var result = {};
 			var now = ts();

			var {root} = PlacesUtils.history.executeQueries([query], 1, options);
			var wasClosed = !root.containerOpen;
			if (wasClosed) root.containerOpen = true;
			for(var ind = 0, max = root.childCount; ind < max; ind++) {
				var {uri} = root.getChild(ind);
				result[uri] = bids(u(uri)).length;
			}
			if (wasClosed) root.containerOpen = false;

			return [result, ts() - now];
		},

		function TEST_SQL_WHILE_LOOP() {

			var sql = "SELECT url, foreign_count" + from;
			var statement = conn.createStatement(sql);

			var result = {};
			var now = ts();

			while(statement.executeStep()) {
				var {row} = statement;
				result[row.url] = row.foreign_count;
			}
			statement.finalize();

			return [result, ts() - now];
		},

		function TEST_SQL_AGG_CUSTOM() {
			var url, onFinal = () => {};

			conn.createAggregateFunction("agg_url", 1, {
				onFinal, onStep: args => url = args.getString(0)
			});
			conn.createAggregateFunction("agg_foreign_count", 1, {
				onFinal, onStep: args => result[url] = args.getInt32(0),
			});

			var sql = "SELECT agg_url(url), agg_foreign_count(foreign_count)" + from;
			var statement = conn.createStatement(sql);

			var result = {};
			var now = ts();

			statement.executeStep();
			statement.finalize();
			conn.removeFunction("agg_url");
			conn.removeFunction("agg_foreign_count");

			return [result, ts() - now];
		},

		function TEST_SQL_AGG_NATIVE() {

			var sql = "SELECT group_concat(url, '\n') urls, group_concat(foreign_count, '\n') fcs" + from;
			var statement = conn.createStatement(sql);

			var result = {};
			var now = ts();

			statement.executeStep();

			var {urls, fcs} = statement.row;
			statement.finalize();

			var num = 0;
			fcs = fcs.split("\n");
			for(var url of urls.split("\n")) result[url] = +fcs[num++];

			return [result, ts() - now];
		}
	];
	var sort = (a, b) => a.num - b.num;
	var pad = Math.max(...testFunctions.map(f => f.name.length)) + 2;

	// Set random order
	for(var func of testFunctions) func.num = Math.random();
	testFunctions.sort(sort);

	var prevResult, prevName, output = [], num = 1;

	for(var func of testFunctions) {
		var {name} = func;
		var [result, time] = func();

		if (prevResult) {
			var keys = Object.keys(result);
			var prevKeys = Object.keys(prevResult);

			if (keys.length != prevKeys.length) {
				console.log(
					"Not same result length!\n" +
					`${name}: ${keys.length}\n${prevName}: ${prevKeys.length}`
				);
				throw "So, test failed";
			}
			for(var key of keys) if (result[key] !== prevResult[key]) console.log(
				`Not same value for ${key}\n` +
				`${name}: ${result[key]}\n${prevName}: ${prevResult[key]}`
			);
		}
		else output.push(Object.keys(result).length + " urls");

		prevName = name;
		prevResult = result;

		var str = new String(num++ + " " + name.padEnd(pad, " ") + time);
		str.num = time;
		output.push(str);
	}
	// Sort out
	output.sort(sort);

	console.log("\n" + output.join("\n"));
})();


Добавлено

sql_stmt.finalize();

Да, точно, finalize()
А то я reset() как-то бездумно у тебя срисовал
из предыдущего кода про sql_stmt. Поправил.

Отредактировано Dumby (24-02-2025 20:02:23)

Отсутствует

 

№1925-02-2025 00:25:21

yup
Участник
 
Группа: Members
Зарегистрирован: 15-04-2016
Сообщений: 1122
UA: Seamonkey 2.49

Re: Странные записи в places.sqlite

Dumby пишет

Не, это я, скорее, к тому, чтобы мне взять уже готовый код, а не сочинять самому.

Сочинение кода (точнее, выбор способа) изменения внешнего вида таблицы было отложено на самый-самый конец. Причина вот какая:


По команде открытия окна истории открывается history.xul, в котором элемент <tree> задан с жёстким перечнем столбцов. К history.xul через chrome.manifest прицеплен my.xul, стартовый код которого должен сделать что-то такое, от чего на экране будет <tree> с ещё одним дополнительным столбцом. Но ведь стартовый код history.xul уже отработал и история показана! И что, всю её удалять и выводить заново (как делает вчерашний код "красящий красным")? Не хочется.


А сделать что-либо с xul-ом до того, как окно открыто, невозможно. Значит, нужно или менять команду, открывающую окно истории, чтобы она сразу my.xul открывала, а в my.xul затащить всё содержимое history.xul (так себе решение), или заранее подменять методы класса, отвечающего за работу с этим <tree>.


Именно последнее и было выбрано. Но тогда сначала нужно научиться получать из БД нужные данные и засовывать их в <tree>, и только потом станет ясно - что, на что и как подменять.


Получать данные вчера научился. Начал думать, что с ними дальше делать - превращать в NavHistoryResult/NavHistoryContainerResultNode/NavHistoryResultNode для скармливания нынешнему PlacesTreeView, или делать custom tree view для работы непосредственно с тем, что возвращает SQL-запрос.


В результате обдумывания получил "двойной удар". Окно истории ведь "живое". Если оно открыто, а пользователь продолжает работать в браузере, то содержимое в окне истории меняется - появляются новые строки, у каких-то имеющихся меняется дата посещения, а у каких-то и имя страницы измениться может. А источником некоторых событий, приводящих к изменениям в окне, является сам объект результатов! Это он сообщает подключённому к нему PlacesTreeView, что что-то изменилось и нужно перевывести. А если у меня только результаты SQL-запроса, то после их получения я уже никак не узнаю, что в БД что-то поменялось. Что, ещё и своё слежение за БД организовывать? Количество кода, который надо добавлять в браузер становится несколько неприличным.
А если преобразовать результаты запроса в NavHistoryContainerResultNode, то от этого слежение за БД всё равно автоматически не появится.


В общем, пока что наиболее реалистичным представляется что-то в духе твоего вчерашнего кода - при выводе/обновлении очередной строки запрашивать, есть ли этот URL в закладках, и дальше (в зависимости от того, что покажется более удобным в пользовании) или менять визуальное представление имеющихся ячеек, или добавить столбец в таблицу, а при выводе/обновлении этой новой ячейки запрашивать isBookmarked и рисовать плюсик.


Некоторое уныние вызывает вот что: я в тот "красящий красным" код в функцию PTV_getCellProperties первой строкой вставил console.log('z'); после чего расположил окна так, что правая сторона консоли была видна из-под окна истории, и поводил мышкой над таблицей истории. Всего лишь поводил. Показания счётчика в строке консоли просто потрясли. И это же не "происки довеска", это родной мозилловский код так работает. Ну да деваться некуда.


Dumby пишет

Кстати, наткнулся на такое:
Обнаружился один урл, для которого foreign_count не совпадает с тем, что отдаёт TEST_XPCOM
В базе значение — три, а кодом без использования чтения базы — два.

Позавчера у меня было предположение, что foreign_count может быть счётчиком не только закладок. Но подозрение пало на записи истории адресной строки. Проверка показала, что нет, те записи на счётчик не влияют. А больше ничего в голову не пришло. Потому что всё остальное, как я считал, ссылается не на moz_places.


Dumby пишет

Оказалось, что добавление к закладке tag'а (метки) увеличивает foreign_count на единицу.

foreign_count, по логике названия, это счётчик внешних ссылок на строку таблицы из других таблиц. Но историю адресной строки я на это дело проверил - не влияет. Значит, только закладки. А сейчас полез проверять всё - и всё оказалось не так.


Dumby пишет

Видимо, PlacesUtils.bookmarks.getBookmarkIdsForURI() отдаёт результат без учёта папки меток.

Dumby пишет

А вот на Iceape — там для такой закладки совпадает, то есть метки учитываются.

В Seamonkey/Iceape закладка кроме URL и имени страницы может содержать метки(tags), краткое имя (keyword) и описание (description).


Описания сидят в отдельной таблице, но на foreign_count не влияют, так как ссылаются на таблицу закладок.


С короткими именами странно - они сидят в отдельной таблице (moz_keywords), индивидуальны для URL (и потому общие для всех закладок, созданных для этого URL) и на foreign_count, как я только что выяснил, влияют даже слишком сильно: если я несколько раз отредактирую текст, то все предыдущие варианты текста так в moz_keywords и останутся, и каждый будет ссылаться на одну и ту же запись в moz_places. При этом ни из moz_places, ни из moz_bookmarks на них ссылок нет, и по какому принципу выбирается, какой вариант показывать, непонятно. Самый последний, что ли?


В общем, у меня сейчас есть один URL в moz_places, три закладки для него в moz_bookmarks и пять записей в moz_keywords. На экране у всех трёх закладок keyword один и тот же, а foreign_count у URL-а - 8.


(Кстати, удалить keyword не удаётся. Редактировать - пожалуйста. Но если пытаюсь удалить полностью - восстанавливается. Всё, что смог - сократить до одной буквы. Наверное, какая-то ошибка в программе. Надо будет глянуть и исправить, если что.)


А с метками вообще чертовщина. Они тоже индивидуальны для URL (и, соответственно, общие для всех закладок, созданных для этого URL), и тоже на foreign_count влияют, но влияют правильно - ввожу у одной из тех трёх закладок, появляется во всех, а счётчик увеличивается на 1. Но при этом я вообще не нашёл, куда метки записываются. Их нет ни в одной таблице!


Dumby пишет

Да, точно, finalize()
А то я reset() как-то бездумно у тебя срисовал из предыдущего кода про sql_stmt.

Не принципиально. Просто вначале я выложил кусок от бОльшего кода, в котором тот фрагмент крутился в цикле, и там выгоднее было использовать reset().
А потом я те эксперименты закончил, цикл стал не нужен, я его удалил и reset() поменял на finalize().
Но поскольку это всё не для рабочего кода, а для "запустить, посмотреть результат, выбросить", то разницы особой нет.

Отсутствует

 

№2025-02-2025 17:08:39

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2309
UA: Firefox 78.0

Re: Странные записи в places.sqlite

yup пишет

Кстати, удалить keyword не удаётся. Редактировать - пожалуйста.
Но если пытаюсь удалить полностью - восстанавливается. Всё, что смог - сократить до одной буквы.
Наверное, какая-то ошибка в программе. Надо будет глянуть и исправить, если что.

Да, я вижу это. Определённо баг. Вот попытка сочинить eval-патч.


Прямо в PlacesEditBookmarkKeywordTransaction (а не по окнам), исходя из предпосылки,
что он не должен допускать описанного тобой бага вообще как таковой.


Код должен исполняться только один раз.
Ну, то есть, из любого разумного окружения, где он будет исполняться только один раз.
Чтобы попробовать, можно запустить разок с консоли.


Понятное дело, что смотреть надо на урле, который не испорчен багом.
То есть, подопытный — урл без кейворда вообще, «и вперёд» после патча.

скрытый текст

Выделить код

Код:

(repl => {
	var url = "resource://gre/modules/PlacesUtils.jsm";
	var g = Components.utils.import(url, {});

	var key = "doTransaction";
	var proto = g.PlacesEditBookmarkKeywordTransaction.prototype;

	proto[key] = g.eval(`(${proto[key]})`.replace(
		"      if (this.item.keyword) {", repl.trimRight()
	));
	console.log("" + proto[key]); // Just log
})(`
      // aOldKeyword may not be provided for unexpected reason.
      this.item.keyword ??= (
        yield PlacesUtils.keywords.fetch({url: this.item.href})
      )?.keyword;\n\n$&
`);

не нашёл, куда метки записываются. Их нет ни в одной таблице!

У себя вижу так:


Создание новой метки образует в таблице moz_bookmarks запись,
представляющую папку (type == 2, надо полагать, папка).


В колонке title у этой папки — имя (текст) метки.
В колонке parent у этой папки, как и у всех других меток,
будет id'шник  корневой папки Tags, той, у которой guid «tags________».


Помимо этого, в той же таблице, образуется запись,
представляющая закладку (type == 1, надо полагать, закладка).


В колонке parent у этой закладки будет id'шник
этой вышеупомянутой папки метки.


А в колонке fk — id'шник уже для другой таблицы, moz_places
в которой под этим id'шником запись с тем урлом, к которому прицеплена метка.


Если задаётся существующая метка,
то тоже самое, но без создания папки для метки.

Отредактировано Dumby (25-02-2025 17:16:58)

Отсутствует

 

Board footer

Powered by PunBB
Modified by Mozilla Russia
Copyright © 2004–2020 Mozilla Russia GitHub mark
Язык отображения форума: [Русский] [English]