(use-package s :straight t) (require 'url) (require 'url-util) (defconst org-movies--omdb-apikey "" "API key for OMDb. Overwrite in custom.el") (defun org-movies--omdb-fetch (url) "Retrieve JSON data from OMDb using URL and return it as an alist. Errors when the request fails or the API reports an error." (let ((buffer (url-retrieve-synchronously url t t))) (unless buffer (error "Failed to contact OMDb")) (with-current-buffer buffer (unwind-protect (progn (goto-char (or (bound-and-true-p url-http-end-of-headers) (point-min))) (let* ((response (decode-coding-string (buffer-substring (point) (point-max)) 'utf-8)) (data (json-read-from-string response))) (when (string= (alist-get "Response" data nil nil #'string=) "False") (error (alist-get "Error" data nil nil #'string=))) data)) (kill-buffer buffer))))) (defun org-movies--extract-title-year () "Return cons of movie title and optional year from current headline." (save-excursion (condition-case nil (progn (org-back-to-heading t) (let* ((raw (org-no-properties (org-get-heading t t t t))) (trimmed (s-trim raw)) (parts (s-match (rx string-start (group (+? any)) (? (seq " " "(" (group (= 4 digit)) ")")) string-end) trimmed))) (cons (s-trim (if parts (nth 1 parts) trimmed)) (when parts (nth 2 parts))))) (error (error "No headline available for movie lookup"))))) (define-minor-mode org-movies-mode "Helper functions for movies.org" :keymap (list (cons (kbd "C-c C-i") #'org-movies-template))) (defun org-movies-template () "Convert imdb url at point to a diary entry." (interactive nil 'org-movies-mode) (let* ((ctx (org-element-context)) (link (when (eq (car ctx) 'link) (plist-get (cadr ctx) :raw-link))) (direct-imdb (and link (nth 1 (s-match (rx "imdb.com/title/" (group "tt" (+ digit))) link)))) (movie (if direct-imdb (org-movies--omdb-fetch (concat "http://omdbapi.com/?apikey=" org-movies--omdb-apikey "&i=" direct-imdb)) (let* ((title-year (org-movies--extract-title-year)) (title-query (car title-year)) (year-query (cdr title-year)) (url (concat "http://omdbapi.com/?apikey=" org-movies--omdb-apikey "&type=movie" "&t=" (url-hexify-string title-query) (if year-query (concat "&y=" (url-hexify-string year-query)) "")))) (org-movies--omdb-fetch url)))) (imdb (or direct-imdb (alist-get "imdbID" movie nil nil #'string=) (error "Missing imdb identifier"))) (title (alist-get "Title" movie nil nil #'string=)) (runtime (alist-get "Runtime" movie nil nil #'string=)) (genre (alist-get "Genre" movie nil nil #'string=)) (director (alist-get "Director" movie nil nil #'string=)) (plot (alist-get "Plot" movie nil nil #'string=)) (poster (alist-get "Poster" movie nil nil #'string=)) (year (alist-get "Year" movie nil nil #'string=))) (pcase (org-element-type (org-element-at-point)) ('headline (ignore)) (_ (beginning-of-line) (kill-line) (org-insert-heading))) (org-edit-headline (concat title " (" year ")")) (org-todo "TODO") (org-set-property "imdb" imdb) (org-set-property "link" (concat "https://imdb.com/title/" imdb)) (org-set-property "runtime" runtime) (org-set-property "genre" genre) (org-set-property "director" director) (org-set-property "plot" plot) (org-set-property "poster" (concat "[[" poster "]]")) )) (org-movies-mode 1)