From 624239dd7ea0a38b64ddfaab2ba1445226cfed2c Mon Sep 17 00:00:00 2001 From: luxick Date: Fri, 10 Oct 2025 16:26:35 +0200 Subject: [PATCH] Add movies.org package --- init.el | 3 ++ org-movies.el | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 org-movies.el diff --git a/init.el b/init.el index aaaec48..e012173 100644 --- a/init.el +++ b/init.el @@ -431,6 +431,9 @@ (when (current-buffer-matches-file-p) (set-buffer-modified-p nil)) (kill-buffer)) +;; movies.org package +(load "~/.emacs.d/org-movies.el" 'noerror) + ;; custom.el - device specific settings (setq custom-file "~/.emacs.d/custom.el") (load custom-file 'noerror) diff --git a/org-movies.el b/org-movies.el new file mode 100644 index 0000000..f3ef748 --- /dev/null +++ b/org-movies.el @@ -0,0 +1,106 @@ +(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 "poster" (concat "[[" poster "]]")) + (org-set-property "plot" plot) + )) + +(org-movies-mode 1) \ No newline at end of file