LINUX.ORG.RU

История изменений

Исправление 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 для получения только заголовка.