1 ;;; navi2ch-list.el --- board list module for navi2ch -*- coding: iso-2022-7bit; lexical-binding: t; -*-
3 ;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 by
6 ;; Author: Taiki SUGAWARA <taiki@users.sourceforge.net>
7 ;; Keywords: network, 2ch
9 ;; This file is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; This file is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING. If not, write to
21 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 ;; Boston, MA 02111-1307, USA.
26 ;; http://salad.2ch.net/bbstable.html \e$B$+$i!":n$C$?J}$,$$$$$s$+$J!#\e(B
29 (provide 'navi2ch-list
)
30 (defconst navi2ch-list-ident
35 (require 'navi2ch-decls
)
36 (require 'navi2ch-inline
))
37 (require 'navi2ch-vars
)
39 (defvar navi2ch-list-mode-map nil
)
40 (unless navi2ch-list-mode-map
41 (let ((map (make-sparse-keymap)))
42 (set-keymap-parent map navi2ch-global-view-map
)
43 (define-key map
"\r" 'navi2ch-list-select-current-board
)
44 (define-key map
"q" 'navi2ch-exit
)
45 (define-key map
"z" 'navi2ch-suspend
)
46 (define-key map
"s" 'navi2ch-list-sync
)
47 (define-key map
" " 'navi2ch-list-select-current-board
)
48 (navi2ch-define-delete-keys map
'scroll-down
)
49 (define-key map
"a" 'navi2ch-list-add-bookmark
)
50 (define-key map
"b" 'navi2ch-list-toggle-bookmark
)
51 (unless (featurep 'xemacs
)
52 (define-key map
[follow-link
] 'mouse-face
))
53 (navi2ch-define-mouse-key map
2 'navi2ch-list-mouse-select
)
54 (define-key map
"/" 'navi2ch-list-toggle-open
)
55 (define-key map
"[" 'navi2ch-list-open-all-category
)
56 (define-key map
"]" 'navi2ch-list-close-all-category
)
57 (define-key map
"D" 'navi2ch-list-delete-global-bookmark
)
58 (define-key map
"C" 'navi2ch-list-change-global-bookmark
)
59 (define-key map
"?" 'navi2ch-list-search
)
60 (define-key map
"e" 'navi2ch-list-expire
)
61 (define-key map
"U" 'navi2ch-list-show-url
)
62 (setq navi2ch-list-mode-map map
)))
64 (defvar navi2ch-list-mode-menu-spec
66 ["Sync board list" navi2ch-list-sync
]
67 ["Toggle offline" navi2ch-toggle-offline
]
68 ["Open all category" navi2ch-list-open-all-category
]
69 ["Close all category" navi2ch-list-close-all-category
]
70 ["Toggle current category" navi2ch-list-toggle-open
]
71 ["Toggle bookmark" navi2ch-list-toggle-bookmark
]
72 ["Select current board" navi2ch-list-select-current-board
])
73 "Menu definition for navi2ch-list.")
75 (defvar navi2ch-list-ignore-category-list
76 '("\e$B%A%c%C%H\e(B" "\e$B$*3($+$-\e(B" "\e$B1?1D0FFb\e(B" "\e$B%D!<%kN`\e(B" "\e$BB>$N7G<(HD\e(B" "\e$BB>$N%5%$%H\e(B" "\e$BFCJL4k2h\e(B"))
77 (defvar navi2ch-list-buffer-name
"*navi2ch list*")
78 (defvar navi2ch-list-current-list nil
)
79 (defvar navi2ch-list-category-list nil
)
80 (defvar navi2ch-list-board-name-list nil
)
82 (defvar navi2ch-list-navi2ch-category-name
"Navi2ch")
83 (defvar navi2ch-list-changed-category-name
"\e$BJQ$o$C$?HD\e(B")
85 (defvar navi2ch-list-navi2ch-category-alist nil
)
87 (defvar navi2ch-list-state-table
88 (navi2ch-alist-to-hash
89 '((add "A" navi2ch-list-add-board-name-face
)
90 (change "C" navi2ch-list-change-board-name-face
)
91 (nil " " navi2ch-list-board-name-face
))))
93 (defconst navi2ch-list-bbstable-default-url
94 (if (fboundp 'json-parse-string
)
95 "https://menu.5ch.net/bbsmenu.json"
96 "https://menu.5ch.net/bbsmenu.html"))
99 (add-hook 'navi2ch-save-status-hook
'navi2ch-list-save-info
)
101 (defun navi2ch-list-get-file-name (&optional name
)
102 (navi2ch-expand-file-name
103 (or name
"board.txt")))
105 (defun navi2ch-list-get-category-list-subr ()
107 (while (re-search-forward "\\(.+\\)\n\\(.+\\)\n\\(.+\\)" nil t
)
109 (list (cons 'name
(match-string 1))
110 (cons 'uri
(match-string 2))
111 (cons 'id
(match-string 3))
117 (defun navi2ch-list-get-category (name list
)
120 (or navi2ch-list-init-open-category
122 (cdr (assoc name navi2ch-list-category-list
))))))
125 (defun navi2ch-list-set-category (name list
)
126 (let ((category (assoc name navi2ch-list-category-list
)))
130 (cons 'child list
))))
131 (setq navi2ch-list-board-name-list
(navi2ch-list-get-board-name-list
132 navi2ch-list-category-list
)))
134 (defun navi2ch-list-get-global-bookmark-board-list ()
136 (list (cons 'name
(cadr x
))
137 (cons 'type
'bookmark
)
139 navi2ch-bookmark-list
))
141 (defun navi2ch-list-get-global-bookmark-category ()
142 (navi2ch-list-get-category
143 navi2ch-list-global-bookmark-category-name
144 (navi2ch-list-get-global-bookmark-board-list)))
146 (defun navi2ch-list-set-global-bookmark-category ()
147 (navi2ch-list-set-category
148 navi2ch-list-global-bookmark-category-name
149 (navi2ch-list-get-global-bookmark-board-list)))
151 (defun navi2ch-list-sync-global-bookmark-category ()
152 (navi2ch-list-set-global-bookmark-category)
153 (let ((buffer-read-only nil
)
156 (navi2ch-list-insert-board-names
157 navi2ch-list-category-list
)
160 (defun navi2ch-list-delete-global-bookmark ()
162 (let ((board (get-text-property (point) 'board
)))
163 (if (eq (cdr (assq 'type board
)) 'bookmark
)
164 (navi2ch-bookmark-delete-bookmark (cdr (assq 'id board
)))
165 (message "This line is not bookmark!"))))
167 (defun navi2ch-list-change-global-bookmark ()
169 (let ((board (get-text-property (point) 'board
)))
170 (if (eq (cdr (assq 'type board
)) 'bookmark
)
171 (navi2ch-bookmark-change-bookmark (cdr (assq 'id board
)))
172 (message "This line is not bookmark!"))))
174 (defun navi2ch-list-get-category-list (file)
175 (when (file-exists-p file
)
177 (navi2ch-insert-file-contents file
)
178 (run-hooks 'navi2ch-list-get-category-list-hook
)
179 (navi2ch-apply-filters navi2ch-list-current-list navi2ch-list-filter-list
)
180 (goto-char (point-min))
182 (while (re-search-forward "\\(.+\\)\n\n\n" nil t
)
183 (setq list
(cons (list (match-string 1)
184 (match-beginning 0) (match-end 0))
186 (goto-char (point-min))
187 (setq list
(nreverse list
))
191 (narrow-to-region (nth 2 (car list
))
192 (or (nth 1 (cadr list
))
195 (navi2ch-list-get-category
197 (navi2ch-list-get-category-list-subr))
199 (setq list
(cdr list
)))
200 (nreverse list2
))))))
202 (defun navi2ch-list-get-etc-category ()
203 (let ((file (expand-file-name navi2ch-list-etc-file-name
205 (when (file-exists-p file
)
207 (insert-file-contents file
)
208 (goto-char (point-min))
209 (navi2ch-list-get-category
210 navi2ch-list-etc-category-name
211 (navi2ch-list-get-category-list-subr))))))
213 (defun navi2ch-list-insert-board-names-subr (list)
215 (indent (make-string (1- navi2ch-list-indent-width
) ?\
))
216 (change (cdr (assq 'change navi2ch-list-current-list
))))
218 (let* ((board-id (cdr (assq 'id board
)))
219 (state (gethash (cdr (assoc board-id change
))
220 navi2ch-list-state-table
)))
223 (cdr (assq 'name board
)))
224 (when navi2ch-list-display-board-id-p
226 (indent-to-column navi2ch-list-board-id-column
)
227 (insert "(" board-id
")"))
229 (set-text-properties prev
(point) nil
)
235 (list 'mouse-face navi2ch-list-mouse-face
236 'face
(cadr state
))))
237 (put-text-property prev
(point) 'board board
)
238 (setq prev
(point)))))
240 (defun navi2ch-list-insert-board-names (list)
241 "LIST \e$B$NFbMF$r%P%C%U%!$KA^F~!#\e(B"
242 (if navi2ch-list-bookmark-mode
243 (navi2ch-list-insert-bookmarks list
)
244 (let ((prev (point)))
246 (let* ((alist (cdr pair
))
247 (open (cdr (assq 'open alist
))))
248 (insert "[" (if open
"-" "+") "]"
250 (set-text-properties prev
(1- (point))
251 (list 'mouse-face navi2ch-list-mouse-face
252 'face
'navi2ch-list-category-face
))
253 (put-text-property prev
(point) 'genre
(car pair
))
255 (navi2ch-list-insert-board-names-subr (cdr (assq 'child alist
))))
256 (setq prev
(point)))))))
258 (defun navi2ch-list-bookmark-node (board)
259 "BOARD \e$B$+$i\e(B bookmark \e$B$K3JG<$9$k\e(B node \e$B$r<hF@$9$k!#\e(B"
260 (let ((uri (cdr (assq 'uri board
)))
261 (type (cdr (assq 'type board
)))
262 (id (cdr (assq 'id board
))))
263 (cond ((eq type
'board
)
268 (defun navi2ch-list-insert-bookmarks (list)
269 (let ((bookmark (cdr (assq 'bookmark navi2ch-list-current-list
)))
271 (dolist (x (navi2ch-list-get-board-name-list list
))
272 (let ((node (navi2ch-list-bookmark-node x
)))
273 (when (member node bookmark
)
274 ;; \e$B%j%9%H$N8e$K$"$k%N!<%I$rM%@h\e(B
275 (setq alist
(delq (assoc node alist
) alist
))
276 (push (cons node x
) alist
))))
277 (navi2ch-list-insert-board-names-subr (mapcar #'cdr
280 (defun navi2ch-list-toggle-open ()
281 "\e$B%+%F%4%j$r3+$$$?$jJD$8$?$j$9$k!#\e(B"
283 (when (save-excursion
285 (re-search-backward "^\\[[+-]\\]" nil t
))
286 (goto-char (match-beginning 0))
287 (let* ((category (get-text-property (point) 'genre
))
288 (props (text-properties-at (point)))
289 (pair (assoc category navi2ch-list-category-list
))
291 (open (cdr (assq 'open alist
)))
292 (buffer-read-only nil
))
293 (delete-region (point) (+ 3 (point)))
294 (insert "[" (if open
"+" "-") "]")
295 (set-text-properties (- (point) 3) (point) props
)
299 (delete-region (point)
300 (if (re-search-forward "^\\[[+-]\\]" nil t
)
303 (navi2ch-list-insert-board-names-subr (cdr (assq 'child alist
)))))
304 (setcdr pair
(navi2ch-put-alist 'open
(not open
) alist
)))))
306 (defun navi2ch-list-select-current-board (&optional force
)
307 "\e$BHD$rA*$V!#$^$?$O%+%F%4%j$N3+JD$r$9$k!#\e(B"
310 (cond ((setq prop
(get-text-property (point) 'board
))
311 (navi2ch-list-select-board prop force
))
312 ((get-text-property (point) 'genre
)
313 (navi2ch-list-toggle-open))
315 (message "Can't select this line!")))))
317 (defun navi2ch-list-open-all-category ()
319 (when (save-excursion
321 (re-search-backward "^\\[[+-]\\]" nil t
))
322 (let ((str (buffer-substring-no-properties
323 (save-excursion (beginning-of-line) (point))
324 (save-excursion (end-of-line) (point)))))
325 (setq navi2ch-list-category-list
327 (navi2ch-put-alist 'open t x
))
328 navi2ch-list-category-list
))
329 (let ((buffer-read-only nil
))
331 (navi2ch-list-insert-board-names
332 navi2ch-list-category-list
))
333 (goto-char (point-min))
334 (re-search-forward (concat "^"
336 (navi2ch-replace-string "^\\[\\+\\]" "[-]"
341 (if (looking-at "\\[-\\]")
342 (goto-char (match-end 0))
343 (forward-char navi2ch-list-indent-width
)))))
345 (defun navi2ch-list-close-all-category ()
347 (when (save-excursion
349 (re-search-backward "^\\[[+-]\\]" nil t
))
350 (goto-char (match-end 0))
351 (let ((str (buffer-substring-no-properties
353 (save-excursion (end-of-line) (point)))))
354 (setq navi2ch-list-category-list
356 (navi2ch-put-alist 'open nil x
))
357 navi2ch-list-category-list
))
358 (let ((buffer-read-only nil
))
360 (navi2ch-list-insert-board-names
361 navi2ch-list-category-list
))
362 (goto-char (point-min))
363 (re-search-forward (concat "^\\(\\[[+-]\\]\\)"
367 (goto-char (match-end 1)))))
369 (defun navi2ch-list-select-board (board &optional force
)
370 (let ((flag (eq (current-buffer)
371 (get-buffer navi2ch-list-buffer-name
))))
372 (when (and (get-buffer navi2ch-board-buffer-name
)
374 (delete-windows-on navi2ch-board-buffer-name
))
375 (dolist (x (navi2ch-article-buffer-list))
377 (delete-windows-on x
)))
378 (navi2ch-split-window 'board
)
379 (navi2ch-bm-select-board board force
)))
381 (easy-menu-define navi2ch-list-mode-menu
382 navi2ch-list-mode-map
383 "Menu used in navi2ch-list"
384 navi2ch-list-mode-menu-spec
)
386 (defun navi2ch-list-setup-menu ()
387 (easy-menu-add navi2ch-list-mode-menu
))
389 (defun navi2ch-list-mode ()
390 "\\{navi2ch-list-mode-map}"
392 (kill-all-local-variables)
393 (setq major-mode
'navi2ch-list-mode
)
394 (setq mode-name
"Navi2ch List")
395 (setq buffer-read-only t
)
396 (buffer-disable-undo)
397 (use-local-map navi2ch-list-mode-map
)
398 (navi2ch-list-setup-menu)
399 (run-hooks 'navi2ch-list-mode-hook
)
400 (force-mode-line-update))
402 (defun navi2ch-list ()
404 (if (get-buffer navi2ch-list-buffer-name
)
405 (switch-to-buffer navi2ch-list-buffer-name
)
406 (switch-to-buffer (get-buffer-create navi2ch-list-buffer-name
))
409 (navi2ch-list-sync nil t
))))
411 (defun navi2ch-list-get-changed-status (old-category-list category-list
)
412 "\e$B0JA0$NHD$N0lMw\e(B OLD-CATEGORY-LIST \e$B$H8=:_$NHD$N0lMw\e(B CATEGORY-LIST \e$B$r\e(B
413 \e$BHf$Y$F!"DI2C
!"JQ99$N$"$C$?HD$r
\e(B
415 (change . changed-list
))
416 \e$B$N
\e(B alist
\e$B$K$
7$FJV$
9!#\e(B
417 added-list
\e$B$O
\e(B '(board-id ...
) \e$B$J
\e(B list
\e$B
!#\e(B
418 changed-list
\e$B$O
\e(B '((board-id old-board new-board
) ...
) \e$B$J
\e(B alist
\e$B
!#\e(B"
419 (let ( ;; \e$B8=:_$NHD0lMw$N\e(B uri \e$B$N\e(B alist
420 (list (navi2ch-alist-list-to-alist
421 (navi2ch-list-get-board-name-list category-list)
423 ;; \e$B0JA0$NHD0lMw$N\e(B uri \e$B$N\e(B alist
424 (old-list (navi2ch-alist-list-to-alist
425 (navi2ch-list-get-board-name-list old-category-list)
427 added-list changed-list)
429 (when (car new) ; uri \e$B$,$"$k$H$-$N$_
=hM
}$
9$k
!#\e(B
430 (let ((old (assoc (car new
) old-list
)))
431 ;; \e$B8=:_$NHD0lMw$N\e(B uri \e$B$,0JA0$NHD0lMw$+$i8+$D$+$i$J$+$C$?$i\e(B
433 (let ((new-name (cdr (assq 'name
(cdr new
))))
434 (new-pure-id (navi2ch-replace-string
435 ":.*" "" (cdr (assq 'id
(cdr new
)))))
436 old-name old-pure-id
)
439 (setq old-name
(cdr (assq 'name
(cdr x
)))
440 old-pure-id
(navi2ch-replace-string
441 ":.*" "" (cdr (assq 'id
(cdr new
)))))
442 ;; \e$BL>A0$H\e(B id \e$B$N\e(B : \e$B0JA0$,F1$8$@$C$?$iJQ$o$C$?HD$KDI2C$9$k\e(B
443 (when (and (string= new-name old-name
)
444 (string= new-pure-id old-pure-id
))
445 (push (list (cdr (assq 'id
(cdr new
)))
449 ;; \e$B8=:_$NHD0lMw$N\e(B id \e$B$,0JA0$NHD0lMw$+$i8+$D$+$i$J$+$C$?$i\e(B
450 ;; \e$BDI2C$5$l$?;v$K$9$k\e(B
451 (push (cdr (assq 'id
(cdr new
))) added-list
)))))))
452 (list (cons 'add added-list
)
453 (cons 'change changed-list
))))
455 (defun navi2ch-list-change (changed-list)
456 "CHANGED-LIST \e$B$r$b$H$KHD%V%C%/%^!<%/$r99?7!#\e(B"
457 (let ((changed-alist (mapcar
459 (cons (navi2ch-list-bookmark-node (nth 1 elt
))
460 (navi2ch-list-bookmark-node (nth 2 elt
))))
462 (setq navi2ch-list-current-list
463 (navi2ch-put-alist 'bookmark
464 (mapcar (lambda (node)
465 (or (cdr (assoc node changed-alist
))
468 navi2ch-list-current-list
)))
469 navi2ch-list-current-list
))))
471 (defun navi2ch-list-apply-changed-status (changed-status)
472 "CHANGED-STATUS \e$B$r$b$H$KHD$NJQ99$r$$$m$s$J=j$KH?1G$9$k!#\e(B"
473 (message "Applying board changes...")
474 (let ((added-list (cdr (assq 'add changed-status
)))
475 (changed-list (cdr (assq 'change changed-status
))))
477 (setq navi2ch-list-current-list
478 (navi2ch-put-alist 'change
479 (append (mapcar (lambda (id)
482 (mapcar (lambda (pair)
483 (cons (car pair
) 'change
))
485 navi2ch-list-current-list
))
486 (navi2ch-change-log-directory changed-list
)
487 (navi2ch-bookmark-change changed-list
)
488 (navi2ch-history-change changed-list
)
489 (navi2ch-list-change changed-list
)
490 (message "Applying board changes...done"))))
492 (defun navi2ch-list-get-changed-category (category-list)
493 (let ((alist (navi2ch-alist-list-to-alist
494 (navi2ch-list-get-board-name-list category-list
)
496 (navi2ch-list-get-category
497 navi2ch-list-changed-category-name
498 (mapcar (lambda (pair)
499 (cdr (assoc (car pair
) alist
)))
500 (cdr (assq 'change navi2ch-list-current-list
))))))
502 (defun navi2ch-list-sync (&optional force first
)
505 (let ((buffer-read-only nil
)
506 (navi2ch-net-force-update (or navi2ch-net-force-update
508 (file (navi2ch-list-get-file-name))
509 (bbstable (or navi2ch-list-bbstable-url
510 navi2ch-list-bbstable-default-url
))
511 (change (cdr (assq 'change navi2ch-list-current-list
)))
512 updated header time old-category-list
)
514 (navi2ch-list-load-info))
515 (navi2ch-set-mode-line-identification)
516 (setq old-category-list
(navi2ch-list-get-normal-category-list
517 navi2ch-list-category-list
))
518 (unless (or navi2ch-offline
520 (not navi2ch-list-sync-update-on-boot
)
521 (file-exists-p file
)))
522 (setq time
(and (equal (cdr (assq 'bbstable navi2ch-list-current-list
))
524 (cdr (assq 'time navi2ch-list-current-list
))))
525 (setq header
(navi2ch-net-update-file bbstable file time
526 'navi2ch-list-make-board-txt
))
527 (setq updated
(and header
528 (not (navi2ch-net-get-state 'not-updated header
))
529 (not (navi2ch-net-get-state 'error header
)))))
531 (setq navi2ch-list-current-list
532 (navi2ch-put-alist 'time
533 (or (cdr (assq 'last-modified header
))
534 (cdr (assq 'date header
)))
535 navi2ch-list-current-list
))
536 (setq navi2ch-list-current-list
537 (navi2ch-put-alist 'bbstable bbstable
538 navi2ch-list-current-list
)))
539 ;; bbstable, etc.txt, navi2ch-list-navi2ch-category-alist
540 ;; \e$B$N$$$:$l$+$,99?7$5$l$F$$$l$P\e(B \e$B0J2<$N=hM}$,I,MW!#\e(B
541 ;; \e$B$H$j$"$($:!">o$K<B9T$7$F$*$/!#\e(B
542 (let ((category-list (navi2ch-list-get-category-list file
)))
543 (when (or updated change
)
544 (navi2ch-list-apply-changed-status
545 (navi2ch-list-get-changed-status old-category-list category-list
)))
546 (setq navi2ch-list-category-list
549 (list (navi2ch-list-get-category
550 navi2ch-list-navi2ch-category-name
551 navi2ch-list-navi2ch-category-alist
)
552 (navi2ch-list-get-global-bookmark-category)
553 (navi2ch-list-get-etc-category)
554 (navi2ch-list-get-changed-category
557 (setq navi2ch-list-board-name-list
558 (navi2ch-list-get-board-name-list
559 navi2ch-list-category-list
)))
561 (navi2ch-list-insert-board-names navi2ch-list-category-list
)))
562 (run-hooks 'navi2ch-list-after-sync-hook
))
564 (defun navi2ch-list-board-id-from-url (url)
565 "URL \e$B$+$i\e(B board-id \e$B$rF@$k!#\e(B"
566 (let ((board-id (cdr (assoc url navi2ch-list-board-id-alist
))))
569 (if (string-match "\\`https?://.+/\\([^/]+\\)/\\'" url
)
570 (match-string 1 url
))))))
573 (defun navi2ch-list-make-board-txt ()
574 (if (and navi2ch-list-media-type
575 (string-equal (cdr navi2ch-list-media-type
) "application/json"))
576 (navi2ch-list-make-board-txt-from-json)
577 (navi2ch-list-make-board-txt-from-html)))
579 (defun navi2ch-list-make-board-txt-from-json ()
580 "bbstable.json \e$B$+$i\e(B (navi2ch \e$BMQ$N\e(B) board.txt \e$B$r:n$k!#\e(B
581 `navi2ch-net-update-file' \e$B$N%O%s%I%i!#\e(B"
582 (let ((coding-system-for-read 'binary
)
583 (coding-system-for-write 'binary
)
586 (id-to-url-table (make-hash-table :test
'eq
))
587 (bbstable (json-parse-string (decode-coding-string (buffer-string) 'utf-8
))))
589 (seq-doseq (category (gethash "menu_list" bbstable
))
590 (let ((category-name (gethash "category_name" category
)))
593 (member category-name navi2ch-list-ignore-category-list
)
594 (insert (encode-coding-string category-name navi2ch-coding-system
) "\n\n\n")
595 (seq-doseq (board (gethash "category_content" category
))
596 (let ((url (gethash "url" board
))
597 (board-name (gethash "board_name" board
))
599 (setq url
(or (cdr (assoc url navi2ch-list-moved-board-alist
))
601 (when (and (navi2ch-list-valid-board url
)
602 (setq board-id
(navi2ch-list-board-id-from-url url
)))
603 (setq id
(intern board-id
))
604 (when (and (setq u
(gethash id id-to-url-table
))
605 (not (string= u url
)))
606 ;; \e$BF1$8\e(B ID \e$B$G\e(B URL \e$B$,0c$&HD$,$"$k>l9g\e(B
609 (while (and (setq newid
(intern (format "%s:%d" id i
)))
610 (setq u
(gethash newid id-to-url-table
))
611 (not (string= u url
)))
614 (insert (encode-coding-string board-name navi2ch-coding-system
) "\n"
615 url
"\n" (symbol-name id
) "\n")))))))))
618 (defun navi2ch-list-make-board-txt-from-html ()
619 "bbstable.html \e$B$+$i\e(B (navi2ch \e$BMQ$N\e(B) board.txt \e$B$r:n$k!#\e(B
620 `navi2ch-net-update-file' \e$B$N%O%s%I%i!#\e(B"
621 (let ((coding-system-for-read 'binary
)
622 (coding-system-for-write 'binary
)
625 (id-to-url-table (make-hash-table :test
'eq
))
627 (when (re-search-forward "<b>[^>]+</b>" nil t
)
628 (goto-char (match-beginning 0))
629 (while (re-search-forward
630 "<\\([ab]\\)\\([^>]*\\)>\\([^<]+\\)</\\1>" nil t
)
631 (let ((tag (match-string 1))
632 (attr (match-string 2))
633 (cont (match-string 3)))
634 (delete-region beg
(point))
635 (if (string-match "a" tag
)
636 (let (url board-id id u
)
637 (when (and (not ignore
)
638 (string-match "href=\"?\\(.+/\\([^/]+\\)/\\)" attr
))
639 (setq url
(match-string 1 attr
))
640 (setq url
(or (cdr (assoc
642 navi2ch-list-moved-board-alist
))
644 (when (and (navi2ch-list-valid-board url
)
645 (setq board-id
(navi2ch-list-board-id-from-url url
)))
646 (setq id
(intern board-id
))
647 (when (and (setq u
(gethash id id-to-url-table
))
648 (not (string= u url
)))
649 ;; \e$BF1$8\e(B ID \e$B$G\e(B URL \e$B$,0c$&HD$,$"$k>l9g\e(B
652 (while (and (setq newid
(intern (format "%s:%d" id i
)))
653 (setq u
(gethash newid id-to-url-table
))
654 (not (string= u url
)))
657 (puthash id url id-to-url-table
)
660 (symbol-name id
) "\n"))))
662 (member (decode-coding-string
663 cont navi2ch-coding-system
)
664 navi2ch-list-ignore-category-list
))
666 (insert cont
"\n\n\n"))))
668 (delete-region beg
(point-max))))
670 (defun navi2ch-list-valid-board (uri)
672 (when (string-match "https?://\\([^/]+\\)/\\([^/]+\\)/" uri
)
673 (let ((host (match-string 1 uri
)))
674 (and (not (string-match navi2ch-list-invalid-host-regexp host
))
675 (string-match navi2ch-list-valid-host-regexp host
))))))
677 (defun navi2ch-list-mouse-select (e)
682 (navi2ch-list-select-current-board)))
684 (defun navi2ch-list-goto-board (&optional default
)
687 (setq alist
(mapcar (lambda (x) (cons (cdr (assq 'id x
)) x
))
688 navi2ch-list-board-name-list
))
689 (save-window-excursion
690 (setq board
(cdr (assoc
694 (format " (%s)" (cdr (assq 'id default
))))
698 (setq board
(or board
699 (assoc (cdr (assq 'id default
)) alist
)))
701 (when (eq (navi2ch-get-major-mode navi2ch-board-buffer-name
)
703 (navi2ch-board-save-info))
704 (navi2ch-list-select-board board
))))
706 (defun navi2ch-list-get-normal-category-list (list)
707 (setq list
(copy-sequence list
)) ; delq \e$B$9$k$+$i\e(B
708 (when (assoc navi2ch-list-navi2ch-category-name list
)
709 (setq list
(delq (assoc navi2ch-list-navi2ch-category-name list
) list
)))
710 (when (assoc navi2ch-list-global-bookmark-category-name list
)
711 (setq list
(delq (assoc navi2ch-list-global-bookmark-category-name list
) list
))))
713 (defun navi2ch-list-get-board-name-list (list)
716 (unless (string= (car x
) navi2ch-list-changed-category-name
)
717 (dolist (y (cdr (assq 'child x
)))
718 (setq id
(cdr (assq 'id y
)))
719 ;; \e$BF1$8\e(B id \e$B$KBP$7$F$O0l$D$N$_JV$9!#\e(B
720 (setq alist
(cons (cons id y
)
721 (delq (assoc id alist
) alist
))))))
722 (mapcar #'cdr
(nreverse alist
))))
724 (defun navi2ch-list-normalize-bookmark (list)
725 (let ((bookmark (cdr (assq 'bookmark list
)))
727 (dolist (x (navi2ch-list-get-board-name-list navi2ch-list-category-list
))
728 (let ((node (navi2ch-list-bookmark-node x
)))
729 (when (member node bookmark
)
730 (setq ret
(cons node
(delq node ret
))))))
733 (defun navi2ch-list-save-info ()
734 (when navi2ch-list-category-list
735 (let ((list (mapcar (lambda (elt)
737 (assq 'open
(cdr elt
))))
738 navi2ch-list-category-list
)))
739 (setq navi2ch-list-current-list
740 (navi2ch-put-alist 'category list
741 navi2ch-list-current-list
))))
742 (when navi2ch-list-current-list
744 (navi2ch-list-get-file-name "list.info")
745 (list (cons 'bookmark
(navi2ch-list-normalize-bookmark
746 navi2ch-list-current-list
))
747 (assq 'category navi2ch-list-current-list
)
748 (assq 'change navi2ch-list-current-list
)
749 (assq 'bbstable navi2ch-list-current-list
)
750 (assq 'time navi2ch-list-current-list
))
753 (defun navi2ch-list-load-info ()
754 (setq navi2ch-list-current-list
755 (navi2ch-load-info (navi2ch-list-get-file-name "list.info")))
756 (if navi2ch-list-load-category-list
757 (setq navi2ch-list-category-list
758 (cdr (assq 'category navi2ch-list-current-list
))))
759 (let* ((file (navi2ch-list-get-file-name))
760 (category-list (navi2ch-list-get-category-list file
)))
761 (setq navi2ch-list-category-list
764 (list (navi2ch-list-get-category
765 navi2ch-list-navi2ch-category-name
766 navi2ch-list-navi2ch-category-alist
)
767 (navi2ch-list-get-global-bookmark-category)
768 (navi2ch-list-get-etc-category)
769 (navi2ch-list-get-changed-category category-list
)))
771 (setq navi2ch-list-board-name-list
772 (navi2ch-list-get-board-name-list navi2ch-list-category-list
))))
774 (defun navi2ch-list-get-current-category-list ()
777 (when (re-search-backward "^\\[[+-]\\]" nil t
)
778 (let ((category (get-text-property (point) 'genre
)))
779 (cdr (assq 'child
(cdr
781 navi2ch-list-category-list
))))))))
784 (defvar navi2ch-list-bookmark-mode nil
)
785 (defvar navi2ch-list-bookmark-mode-map nil
)
786 (unless navi2ch-list-bookmark-mode-map
787 (setq navi2ch-list-bookmark-mode-map
(make-sparse-keymap))
788 (define-key navi2ch-list-bookmark-mode-map
"d"
789 'navi2ch-list-delete-bookmark
)
790 (define-key navi2ch-list-bookmark-mode-map
"a" 'undefined
))
792 (navi2ch-set-minor-mode 'navi2ch-list-bookmark-mode
794 navi2ch-list-bookmark-mode-map
)
796 (defun navi2ch-list-add-bookmark ()
798 (let ((node (navi2ch-list-bookmark-node (get-text-property (point)
800 (list (cdr (assq 'bookmark navi2ch-list-current-list
))))
802 (unless (member node list
)
803 (setq list
(cons node list
))
804 (setq navi2ch-list-current-list
805 (navi2ch-put-alist 'bookmark list
806 navi2ch-list-current-list
))
807 (message "Add bookmark"))
808 (message "Can't select this line!"))))
810 (defun navi2ch-list-delete-bookmark ()
812 (let ((node (navi2ch-list-bookmark-node (get-text-property (point)
814 (list (cdr (assq 'bookmark navi2ch-list-current-list
))))
817 (setq list
(delete node list
))
818 (setq navi2ch-list-current-list
819 (navi2ch-put-alist 'bookmark list
820 navi2ch-board-current-board
))
821 (let ((buffer-read-only nil
))
822 (delete-region (save-excursion (beginning-of-line) (point))
823 (save-excursion (forward-line) (point))))
824 (message "Delete bookmark"))
825 (message "Can't select this line!"))))
827 (defun navi2ch-list-toggle-bookmark ()
829 (setq navi2ch-list-bookmark-mode
(not navi2ch-list-bookmark-mode
))
830 (let ((buffer-read-only nil
))
833 (navi2ch-list-insert-board-names navi2ch-list-category-list
))))
836 (defun navi2ch-list-search-current-board-subject ()
838 (navi2ch-search-subject-subr (list (get-text-property (point) 'board
))))
840 (defun navi2ch-list-search-current-category-subject ()
842 (navi2ch-search-subject-subr
843 (navi2ch-list-get-current-category-list)))
845 (defun navi2ch-list-search-current-board-article ()
847 (navi2ch-search-article-subr (list (get-text-property (point) 'board
))))
849 (defun navi2ch-list-search-current-category-article ()
851 (navi2ch-search-article-subr
852 (navi2ch-list-get-current-category-list)))
854 (defun navi2ch-list-search-current-board-cache ()
856 (navi2ch-search-cache-subr (list (get-text-property (point) 'board
))))
858 (defun navi2ch-list-search-current-category-cache ()
860 (navi2ch-search-cache-subr
861 (navi2ch-list-get-current-category-list)))
863 (defun navi2ch-list-search-current-board-orphan ()
865 (navi2ch-search-orphan-subr (list (get-text-property (point) 'board
))))
867 (defun navi2ch-list-search-current-category-orphan ()
869 (navi2ch-search-orphan-subr
870 (navi2ch-list-get-current-category-list)))
872 (defun navi2ch-list-search ()
874 (let* ((ch (navi2ch-read-char-with-retry
875 "Search for: s)ubject a)rticle c)ache o)rphan: "
877 (board (get-text-property (point) 'board
))
880 (navi2ch-board-get-file-name board
))
881 (navi2ch-read-char-with-retry
882 "Search from: b)oard c)ategory l)ocal w)eb: "
884 (navi2ch-read-char-with-retry
885 "Search from: c)ategory l)ocal w)eb: " nil
'(?c ?l ?w
)))
887 (navi2ch-board-get-file-name board
))
888 (navi2ch-read-char-with-retry
889 "Search from: b)oard c)ategory l)ocal: " nil
'(?b ?c ?l
))
890 (navi2ch-read-char-with-retry
891 "Search from: c)ategory l)ocal: " nil
'(?c ?l
))))))
893 (cond ((eq ch2 ?b
) (navi2ch-list-search-current-board-subject))
894 ((eq ch2 ?c
) (navi2ch-list-search-current-category-subject))
895 ((eq ch2 ?l
) (navi2ch-search-all-subject))
896 ((eq ch2 ?w
) (navi2ch-search-web))))
898 (cond ((eq ch2 ?b
) (navi2ch-list-search-current-board-article))
899 ((eq ch2 ?c
) (navi2ch-list-search-current-category-article))
900 ((eq ch2 ?l
) (navi2ch-search-all-article))))
902 (cond ((eq ch2 ?b
) (navi2ch-list-search-current-board-cache))
903 ((eq ch2 ?c
) (navi2ch-list-search-current-category-cache))
904 ((eq ch2 ?l
) (navi2ch-search-all-cache))))
906 (cond ((eq ch2 ?b
) (navi2ch-list-search-current-board-orphan))
907 ((eq ch2 ?c
) (navi2ch-list-search-current-category-orphan))
908 ((eq ch2 ?l
) (navi2ch-search-all-orphan)))))))
911 (defun navi2ch-list-expire-current-board (&optional ask
)
913 (navi2ch-board-expire
914 (get-text-property (point) 'board
) ask
))
916 (defun navi2ch-list-expire-current-category (&optional ask
)
918 (and (interactive-p) (setq ask t
))
920 (y-or-n-p "Expire current category boards? "))
921 (dolist (board (navi2ch-list-get-current-category-list))
922 (navi2ch-board-expire board
))
923 (message "Expiring current category is done")))
925 (defun navi2ch-list-expire-all (&optional ask
)
927 (and (interactive-p) (setq ask t
))
929 (y-or-n-p "Expire all boards? "))
930 (dolist (board navi2ch-list-board-name-list
)
931 (when (eq (cdr (assq 'type board
)) 'board
)
932 (navi2ch-board-expire board
)))
933 (message "Expiring all board is done")))
935 (defun navi2ch-list-expire ()
937 (let ((ch (navi2ch-read-char-with-retry "Expire b)oard c)ategory a)ll? "
939 (cond ((eq ch ?b
) (navi2ch-list-expire-current-board 'ask
))
940 ((eq ch ?c
) (navi2ch-list-expire-current-category 'ask
))
941 ((eq ch ?a
) (navi2ch-list-expire-all 'ask
)))))
943 (defun navi2ch-list-show-url ()
945 (let* ((board (get-text-property (point) 'board
))
946 (uri (cdr (assq 'uri board
)))
947 (name (cdr (assq 'name board
))))
949 (message "Can't select this line!")
950 (let ((char (navi2ch-read-char-with-retry
951 (format "c)opy v)iew t)itle u)rl&title? URL: %s: " uri
)
952 nil
'(?c ?v ?t ?u
))))
954 (navi2ch-browse-url-internal uri
)
955 (let ((str (cond ((eq char ?c
)
960 (format "%s\n%s" name uri
)))))
964 (message "Copy: %s" str
))))))))
966 (defun navi2ch-list-url-at-point (point)
967 (let ((board (get-text-property point
'board
)))
968 (cdr (assq 'uri board
))))
970 (run-hooks 'navi2ch-list-load-hook
)
971 ;;; navi2ch-list.el ends here