История изменений
Исправление Zubok, (текущая версия) :
да, url-insert работает:
Угу. Я сейчас попробовал у себя наконец-то. Заметил одну непокрытую проблему. Есть сайты, которые кодировку не передают (плохо себя ведут, да), поэтому перекодировка обламывается. В случае отсутствия кодировки url-insert передает как есть, не перекодирует, а проверять теги <meta> в тексте страницы не обучен. И вот тут облом. Например, взял японский https://rakuten.co.jp, а он не передает charset= в хидере. Поэтому возвращается однобайтовый заголовок. Я думаю, что парсить <meta> пока не стоит. Проще можно считать charset по умолчанию utf-8, если нет кодировки. Это должно покрыть большинство случаев, кроме случаев, когда сайт в странной кодировке и она не указана в хидере, а только в <meta> (такие запросто могут встетиться). Можно просто сделать буфер data-buffer мультибайтным. Тогда rakuten.co.jp нормально заголовок отдает.
(defun org-link-describe (url &optional descr)
(with-temp-buffer
(let ((data-buffer (url-retrieve-synchronously url)))
(with-current-buffer data-buffer
(set-buffer-multibyte t))
(url-insert data-buffer)
(kill-buffer data-buffer)
(goto-char (point-min))
(if (re-search-forward "<title>\\([^<]+?\\)</title>")
(match-string-no-properties 1)))))
Мне только не нравится, что этот url-insert перекодирует весь большой сайт, создавая еще один большой буфер, когда надо перекодировать только заголовок. Обратил внимание на аргументы BEG и END у url-insert. Вроде показалось, что можно воспользоваться и проставить (match-beginning 1) и (match-end 1) вместо них. И кажется, что перекодируется только <title>. Проверил — нифига. Не совсем ясно написано в документации. Эксперимент показывает, что это начало и конец кусочка непосредствено в теле странички, а не во всем буфере вместе с хендлом и страничкой (BEG and END can be used to only insert a subpart of the body. They count bytes from the beginning of the body). Получается как-то нелогично немного. Чтобы правильно проставить BEG и END, надо разбить data-buffer на заголовки и сам HTML, искать title в нем, найти начало конец и передавать в url-insert. Как-то так себе. В общем, можно переписать на более низком уровне (топикстартеру: по примененным функциям см. Emacs MIME).
(defun org-link-describe (url &optional descr)
(let* ((handle (with-current-buffer (url-retrieve-synchronously url)
(mm-dissect-buffer t)))
(charset (mail-content-type-get (mm-handle-type handle) 'charset))
(title (with-current-buffer (mm-handle-buffer handle)
(goto-char (point-min))
(re-search-forward "<title>\\([^<]+?\\)</title>")
(match-string-no-properties 1))))
(mm-destroy-parts handle)
(unless charset
(setq charset "utf-8"))
(mm-decode-string title (mm-charset-to-coding-system charset))))
Можно вместо подстановки «utf-8» по умолчанию еще сделать выпарсивание <meta ... charset=...>. Я этого не сделал.
Есть еще вариант - w3m-retrieve. Так как это браузер, то он по идее должен все перекодировать и по заголовку и по <meta>. Только я еще не проверил. Может, и не получится. Но w3m — это в любом случае overhead для получения только заголовка.
Исходная версия Zubok, :
да, url-insert работает:
Угу. Я сейчас попробовал у себя наконец-то. Заметил одну непокрытую проблему. Есть сайты, которые кодировку не передают (плохо себя ведут, да), поэтому перекодировка обламывается. В случае отсутствия кодировки url-insert передает как есть, не перекодирует, а проверять теги <meta> в тексте страницы не обучен. И вот тут облом. Например, взял японский https://rakuten.co.jp, а он не передает charset= в хидере. Поэтому возвращается однобайтовый заголовок. Я думаю, что парсить <meta> пока не стоит. Проще можно считать charset по умолчанию utf-8, если нет кодировки. Это должно покрыть большинство случаев, кроме случаев, когда сайт в странной кодировке и она не указана в хидере, а только в <meta> (такие запросто могут встетиться). Можно просто сделать буфер data-buffer мультибайтным. Тогда rakuten.co.jp нормально заголовок отдает.
(defun org-link-describe (url &optional descr)
(with-temp-buffer
(let ((data-buffer (url-retrieve-synchronously url)))
(with-current-buffer data-buffer
(set-buffer-multibyte t))
(url-insert data-buffer)
(kill-buffer data-buffer)
(goto-char (point-min))
(if (re-search-forward "<title>\\([^<]+?\\)</title>")
(match-string-no-properties 1)))))
Мне только не нравится, что этот url-insert перекодирует весь большой сайт, создавая еще один большой буфер, когда надо перекодировать только заголовок. Обратил внимание на аргументы BEG и END у url-insert. Вроде показалось, что можно воспользоваться и проставить (match-beginning 1) и (match-end 1) вместо них. И кажется, что перекодируется только <title>. Проверил — нифига. Не совсем ясно написано в документации. Эксперимент показывает, что это начало и конец кусочка непосредствено в теле странички, а не во всем буфере вместе с хендлом и страничкой. Получается как-то нелогично немного. Чтобы правильно проставить BEG и END, надо разбить data-buffer на заголовки и сам HTML, искать title в нем, найти начало конец и передавать в url-insert. Как-то так себе. В общем, можно переписать на более низком уровне (топикстартеру: по примененным функциям см. Emacs MIME).
(defun org-link-describe (url &optional descr)
(let* ((handle (with-current-buffer (url-retrieve-synchronously url)
(mm-dissect-buffer t)))
(charset (mail-content-type-get (mm-handle-type handle) 'charset))
(title (with-current-buffer (mm-handle-buffer handle)
(goto-char (point-min))
(re-search-forward "<title>\\([^<]+?\\)</title>")
(match-string-no-properties 1))))
(mm-destroy-parts handle)
(unless charset
(setq charset "utf-8"))
(mm-decode-string title (mm-charset-to-coding-system charset))))
Можно вместо подстановки «utf-8» по умолчанию еще сделать выпарсивание <meta ... charset=...>. Я этого не сделал.
Есть еще вариант - w3m-retrieve. Так как это браузер, то он по идее должен все перекодировать и по заголовку и по <meta>. Только я еще не проверил. Может, и не получится. Но w3m — это в любом случае overhead для получения только заголовка.