Skip to content

Instantly share code, notes, and snippets.

@vonavi
Last active December 21, 2023 21:38
Show Gist options
  • Save vonavi/68b7c4c4ef50bc43e42198635e205f81 to your computer and use it in GitHub Desktop.
Save vonavi/68b7c4c4ef50bc43e42198635e205f81 to your computer and use it in GitHub Desktop.
Dump LiveJournal posts and comments
;;; ljdump-async.el --- Dump LiveJournal posts and comments -*- lexical-binding: t; -*-
;; Copyright (C) 2021 Vladimir Ivanov
;; Author: Vladimir Ivanov <ivvl82@gmail.com>
;; Keywords:
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;
;;; Code:
(require 'cl-lib)
(require 'url)
(defconst livejournal-api-url "https://www.livejournal.com/interface/flat")
(defvar livejournal-auth-file "auth.txt")
(defun livejournal-parse-response (status callback)
(when (not status)
(error "Could not reach LiveJournal endpoint"))
(let* ((resp-alist (lambda (str)
(cl-loop for (k v)
on (split-string (string-trim str) "\n")
by #'cddr
while v
collect (cons (intern k) v))))
(resp (funcall resp-alist (buffer-substring-no-properties
(1+ url-http-end-of-headers)
(point-max)))))
(if (string= "OK" (alist-get 'success resp))
(funcall callback resp)
(user-error (alist-get 'errmsg resp)))))
(defun livejournal-retrieve (data callback)
(let ((url-request-method "POST")
(url-request-extra-headers
'(("Content-type" . "application/x-www-form-urlencoded")))
(url-request-data (mapconcat (lambda (kv)
(concat (symbol-name (car kv))
"="
(url-hexify-string (cdr kv))))
data
"&")))
(url-retrieve livejournal-api-url
#'livejournal-parse-response
(list callback))))
(defun livejournal-challenge (callback)
(livejournal-retrieve '((mode . "getchallenge"))
(lambda (data)
(funcall callback (alist-get 'challenge data)))))
(defun livejournal-getevents (challenge callback)
(let ((auth (split-string
(string-trim (with-temp-buffer
(insert-file-contents livejournal-auth-file)
(buffer-string)))
":")))
(livejournal-retrieve
`((mode . "getevents")
(user . ,(car auth))
(auth_method . "challenge")
(auth_challenge . ,challenge)
(auth_response . ,(md5 (concat challenge (md5 (cadr auth)))))
(selecttype . "lastn")
(howmany . "1")
(usejournal . "justy-tylor"))
callback)))
(defun ljdump-async ()
(interactive)
(livejournal-challenge
(lambda (challenge)
(livejournal-getevents challenge #'prin1))))
(provide 'ljdump-async)
;;; ljdump-async.el ends here
;;; ljdump-sync.el --- Dump LiveJournal posts and comments -*- lexical-binding: t; -*-
;; Copyright (C) 2021 Vladimir Ivanov
;; Author: Vladimir Ivanov <ivvl82@gmail.com>
;; Keywords:
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;
;;; Code:
(require 'cl-lib)
(require 'url)
(defconst livejournal-api-url "https://www.livejournal.com/interface/flat")
(defvar livejournal-auth-file "auth.txt")
(defun livejournal-parse-response ()
(let* ((resp-alist (lambda (str)
(cl-loop for (k v)
on (split-string (string-trim str) "\n")
by #'cddr
while v
collect (cons (intern k) v))))
(resp (funcall resp-alist (buffer-substring-no-properties
(1+ url-http-end-of-headers)
(point-max)))))
(if (string= "OK" (alist-get 'success resp))
resp
(user-error (alist-get 'errmsg resp)))))
(defun livejournal-retrieve (data)
(let ((url-request-method "POST")
(url-request-extra-headers
'(("Content-type" . "application/x-www-form-urlencoded")))
(url-request-data (mapconcat (lambda (kv)
(concat (symbol-name (car kv))
"="
(url-hexify-string (cdr kv))))
data
"&")))
(with-current-buffer (url-retrieve-synchronously livejournal-api-url)
(livejournal-parse-response))))
(defun livejournal-challenge ()
(alist-get 'challenge (livejournal-retrieve '((mode . "getchallenge")))))
(defun livejournal-getevents (challenge)
(let ((auth (split-string
(string-trim (with-temp-buffer
(insert-file-contents livejournal-auth-file)
(buffer-string)))
":")))
(livejournal-retrieve
`((mode . "getevents")
(user . ,(car auth))
(auth_method . "challenge")
(auth_challenge . ,challenge)
(auth_response . ,(md5 (concat challenge (md5 (cadr auth)))))
(selecttype . "lastn")
(howmany . "1")
(usejournal . "justy-tylor")))))
(defun ljdump-sync ()
(interactive)
(prin1
(livejournal-getevents
(livejournal-challenge))))
(provide 'ljdump-sync)
;;; ljdump-sync.el ends here
@vonavi
Copy link
Author

vonavi commented Feb 23, 2021

Store your LiveJournal's credentials as <login>:<password> in auth.txt in the same directory. Try ljdump-async or ljdump-sync to get LiveJournal events.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment