1 ;;; newst-reader.el --- Generic RSS reader functions.
3 ;; Copyright (C) 2003-2017 Free Software Foundation, Inc.
5 ;; Author: Ulf Jasper <ulf.jasper@web.de>
6 ;; Filename: newst-reader.el
7 ;; URL: http://www.nongnu.org/newsticker
10 ;; ======================================================================
12 ;; This file is part of GNU Emacs.
14 ;; GNU Emacs is free software: you can redistribute it and/or modify
15 ;; it under the terms of the GNU General Public License as published by
16 ;; the Free Software Foundation, either version 3 of the License, or
17 ;; (at your option) any later version.
19 ;; GNU Emacs is distributed in the hope that it will be useful,
20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ;; GNU General Public License for more details.
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
27 ;; ======================================================================
32 ;; ======================================================================
35 (require 'newst-backend
)
37 ;; ======================================================================
39 ;; ======================================================================
40 (defun newsticker--set-customvar-formatting (symbol value
)
41 "Set newsticker-variable SYMBOL value to VALUE.
42 Calls all actions which are necessary in order to make the new
44 (if (or (not (boundp symbol
))
45 (equal (symbol-value symbol
) value
))
47 ;; something must have changed
49 (when (fboundp 'newsticker--forget-preformatted
)
50 (newsticker--forget-preformatted))))
52 ;; ======================================================================
54 (defgroup newsticker-reader nil
55 "Settings for the feed reader."
58 (defcustom newsticker-frontend
60 "Newsticker frontend for reading news.
61 This must be one of the functions `newsticker-plainview' or
62 `newsticker-treeview'."
63 :type
'(choice :tag
"Frontend"
64 (const :tag
"Single buffer (plainview)" newsticker-plainview
)
65 (const :tag
"Tree view (treeview)" newsticker-treeview
))
66 :group
'newsticker-reader
)
68 ;; image related things
69 (defcustom newsticker-download-logos
71 "If non-nil newsticker downloads logo images of subscribed feeds."
74 :group
'newsticker-reader
)
76 (defcustom newsticker-enable-logo-manipulations
78 "If non-nil newsticker manipulates logo images.
79 This enables the following image properties: heuristic mask for all
80 logos, and laplace-conversion for images without new items."
82 :group
'newsticker-reader
)
84 (defcustom newsticker-justification
86 "How to fill item descriptions.
87 If non-nil newsticker calls `fill-region' to wrap long lines in
88 item descriptions. However, if an item description contains HTML
89 text and `newsticker-html-renderer' is non-nil, filling is not
91 :type
'(choice :tag
"Justification"
92 (const :tag
"No filling" nil
)
93 (const :tag
"Left" left
)
94 (const :tag
"Right" right
)
95 (const :tag
"Center" center
)
96 (const :tag
"Full" full
))
97 :set
'newsticker--set-customvar-formatting
98 :group
'newsticker-reader
)
100 (defcustom newsticker-use-full-width
102 "Decides whether to use the full window width when filling.
103 If non-nil newsticker sets `fill-column' so that the whole
104 window is used when filling. See also `newsticker-justification'."
106 :set
'newsticker--set-customvar-formatting
107 :group
'newsticker-reader
)
109 (defcustom newsticker-html-renderer
110 (if (fboundp 'libxml-parse-html-region
)
112 "Function for rendering HTML contents.
113 If non-nil, newsticker.el will call this function whenever it
114 finds HTML-like tags in item descriptions.
115 Possible functions include `shr-render-region', `w3m-region', `w3-region', and
116 `newsticker-htmlr-render'.
117 Newsticker automatically loads the respective package w3m, w3, or
118 htmlr if this option is set."
119 :type
'(choice :tag
"Function"
120 (const :tag
"None" nil
)
121 (const :tag
"SHR" shr-render-region
)
122 (const :tag
"w3" w3-region
)
123 (const :tag
"w3m" w3m-region
)
124 (const :tag
"htmlr" newsticker-htmlr-render
))
125 :set
'newsticker--set-customvar-formatting
126 :group
'newsticker-reader
)
128 (defcustom newsticker-date-format
130 "Format for the date part in item and feed lines.
131 See `format-time-string' for a list of valid specifiers."
133 :set
'newsticker--set-customvar-formatting
134 :group
'newsticker-reader
)
136 (defgroup newsticker-faces nil
137 "Settings for the faces of the feed reader."
138 :group
'newsticker-reader
)
140 (defface newsticker-feed-face
141 '((default :weight bold
:height
1.2)
142 (((class color
) (background dark
)) :foreground
"white")
143 (((class color
) (background light
)) :foreground
"black"))
144 "Face for news feeds."
145 :group
'newsticker-faces
)
147 (defface newsticker-extra-face
148 '((default :slant italic
:height
0.8)
149 (((class color
) (background dark
)) :foreground
"gray50")
150 (((class color
) (background light
)) :foreground
"gray50"))
151 "Face for newsticker dates."
152 :group
'newsticker-faces
)
154 (defface newsticker-enclosure-face
155 '((default :weight bold
)
156 (((class color
) (background dark
)) :background
"orange")
157 (((class color
) (background light
)) :background
"orange"))
158 "Face for enclosed elements."
159 :group
'newsticker-faces
)
161 ;; ======================================================================
162 ;;; Utility functions
163 ;; ======================================================================
164 (defun newsticker--insert-enclosure (item keymap
)
165 "Insert enclosure element of a news ITEM into the current buffer.
166 KEYMAP will be applied."
167 (let ((enclosure (newsticker--enclosure item
))
170 (let ((url (cdr (assoc 'url enclosure
)))
171 (length (string-to-number (or (cdr (assoc 'length enclosure
))
173 (type (cdr (assoc 'type enclosure
))))
174 (cond ((> length
1048576)
175 (insert (format "Enclosed file (%s, %1.2f MBytes)" type
176 (/ length
1048576))))
178 (insert (format "Enclosed file (%s, %1.2f KBytes)" type
181 (insert (format "Enclosed file (%s, %1.2f Bytes)" type
184 (insert (format "Enclosed file (%s, unknown size)" type
))))
185 (add-text-properties beg
(point)
186 (list 'mouse-face
'highlight
189 "mouse-2: visit (%s)" url
)
195 (defun newsticker--print-extra-elements (item keymap
&optional htmlish
)
196 "Insert extra-elements of ITEM in a pretty form into the current buffer.
197 KEYMAP is applied. If HTMLISH is non-nil then HTML-markup is used
199 (let ((ignored-elements '(items link title description content
200 content
:encoded encoded
202 dc
:date date entry item guid pubDate
205 (left-column-width 1))
206 (if htmlish
(insert "<ul>"))
207 (mapc (lambda (extra-element)
208 (when (listp extra-element
) ;; take care of broken xml
210 (unless (memq (car extra-element
) ignored-elements
)
211 (setq left-column-width
(max left-column-width
213 (car extra-element
))))))))
214 (newsticker--extra item
))
215 (mapc (lambda (extra-element)
216 (when (listp extra-element
) ;; take care of broken xml
218 (unless (memq (car extra-element
) ignored-elements
)
219 (newsticker--do-print-extra-element extra-element
223 (newsticker--extra item
))
224 (if htmlish
(insert "</ul>"))))
226 (defun newsticker--do-print-extra-element (extra-element width keymap htmlish
)
227 "Actually print an EXTRA-ELEMENT using the given WIDTH.
228 KEYMAP is applied. If HTMLISH is non-nil then HTML-markup is used
230 (let ((name (symbol-name (car extra-element
))))
232 (insert (format "<li>%s: " name
))
233 (insert (format "%s: " name
))
234 (insert (make-string (- width
(length name
)) ?
))))
235 (let (;;(attributes (cadr extra-element)) ;FIXME!!!!
236 (contents (cddr extra-element
)))
237 (cond ((listp contents
)
240 (string-match "^http://.*" i
))
242 (insert i
" ") ; avoid self-reference from the
246 (list 'mouse-face
'highlight
249 (format "mouse-2: visit (%s)" i
)
251 (insert (format "%s" i
))))
254 (insert (format "%s" contents
))))
259 (defun newsticker--image-read (feed-name-symbol disabled
&optional max-height
)
260 "Read the cached image for FEED-NAME-SYMBOL from disk.
261 If DISABLED is non-nil the image will be converted to a disabled look
262 \(unless `newsticker-enable-logo-manipulations' is not t).
263 Optional argument MAX-HEIGHT specifies the maximal image height.
265 (let ((image-name (concat (newsticker--images-dir)
266 (symbol-name feed-name-symbol
))))
267 (when (file-exists-p image-name
)
268 (condition-case error-data
271 (and (fboundp 'imagemagick-types
)
275 :conversion
(and newsticker-enable-logo-manipulations
278 :mask
(and newsticker-enable-logo-manipulations
281 :max-height max-height
)
283 (message "Error: cannot create image for %s: %s"
284 feed-name-symbol error-data
))))))
286 (defun newsticker--icon-read (feed-name-symbol)
287 "Read the cached icon for FEED-NAME-SYMBOL from disk.
290 (when (file-exists-p (newsticker--icons-dir))
291 (dolist (file (directory-files (newsticker--icons-dir) t
292 (concat (symbol-name feed-name-symbol
) "\\..*")))
293 (condition-case error-data
294 (throw 'icon
(create-image
295 file
(and (fboundp 'imagemagick-types
)
303 (message "Error: cannot create icon for %s: %s"
304 feed-name-symbol error-data
)))))
305 ;; Fallback: default icon.
306 (find-image '((:type png
:file
"newsticker/rss-feed.png" :ascent center
)))))
308 ;; the functions we need for retrieval and display
310 (defun newsticker-show-news ()
311 "Start reading news. You may want to bind this to a key."
313 (newsticker-start t
) ;; will start only if not running
314 ;; Load the html rendering packages
315 (if newsticker-html-renderer
316 (cond ((eq newsticker-html-renderer
'w3m-region
)
318 ((eq newsticker-html-renderer
'w3-region
)
320 ((eq newsticker-html-renderer
'newsticker-htmlr-render
)
322 (funcall newsticker-frontend
))
324 ;; ======================================================================
326 ;; ======================================================================
328 (defun newsticker-browse-url-item (feed item
)
329 "Convert FEED ITEM to html and call `browse-url' on result."
331 (let ((t-file (make-temp-file "newsticker")))
332 (with-temp-file t-file
333 (insert "<?xml version=\"1.0\" encoding=\"utf-8\"?>
334 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"
335 \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">
336 <html xmlns=\"http://www.w3.org/1999/xhtml\">
338 (insert "<h1>" feed
": " (newsticker--title item
) "</h1>")
339 (insert (format-time-string newsticker-date-format
340 (newsticker--time item
)))
342 (insert (or (newsticker--desc item
) "[No Description]"))
343 (when (newsticker--enclosure item
)
344 (insert "<br/><hr/><i>")
345 (newsticker--insert-enclosure item nil
)
347 (when (newsticker--extra item
)
348 (insert "<br/><hr/><tt>")
349 (newsticker--print-extra-elements item nil
)
351 (insert "</body></html>"))
352 (browse-url t-file
)))
354 (provide 'newst-reader
)
356 ;;; newst-reader.el ends here