plumb

A URL menu for Emacs
git clone https://git.jamzattack.xyz/plumb
Log | Files | Refs | LICENSE

plumb.el (7073B)


      1 ;;; plumb.el --- Interactively select how to use a URL  -*- lexical-binding: t; -*-
      2 
      3 ;; Copyright (C) 2020  Jamie Beardslee
      4 
      5 ;; Author: Jamie Beardslee <jdb@jamzattack.xyz>
      6 ;; URL: https://git.jamzattack.xyz/plumb
      7 ;; Keywords: convenience
      8 ;; Package-Requires: ((emacs "26.1"))
      9 ;; Version: 2020.11.17
     10 
     11 ;; This file is not part of GNU Emacs.
     12 
     13 ;; This program is free software; you can redistribute it and/or modify
     14 ;; it under the terms of the GNU General Public License as published by
     15 ;; the Free Software Foundation, either version 3 of the License, or
     16 ;; (at your option) any later version.
     17 
     18 ;; This program is distributed in the hope that it will be useful,
     19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     21 ;; GNU General Public License for more details.
     22 
     23 ;; You should have received a copy of the GNU General Public License
     24 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
     25 
     26 ;;; Commentary:
     27 
     28 ;; This package defines a few functions to handle a URL.  The main
     29 ;; entry-point `plumb' prompts for an action to run on the URL at
     30 ;; point.
     31 
     32 ;;; Code:
     33 
     34 (require 'url)
     35 (require 'pcase)
     36 (require 'thingatpt)
     37 (require 'shr)
     38 
     39 (defgroup plumb ()
     40   "URL Menu."
     41   :link '(url-link "https://git.jamzattack.xyz/plumb")
     42   :group 'comm)
     43 
     44 (defcustom plumb-audio-directory "~/Music/"
     45   "The directory in which to download music using `plumb'."
     46   :type 'directory
     47   :group 'plumb)
     48 
     49 (defcustom plumb-video-directory "~/Videos/"
     50   "The directory in which to download videos using `plumb'."
     51   :type 'directory
     52   :group 'plumb)
     53 
     54 (defcustom plumb-image-directory "~/Pictures/"
     55   "The directory in which do download images using `plumb'."
     56   :type 'directory
     57   :group 'plumb)
     58 
     59 (defcustom plumb-pdf-directory "~/Documents/"
     60   "The directory in which do download pdfs using `plumb'."
     61   :type 'directory
     62   :group 'plumb)
     63 
     64 (defcustom plumb-mpv-default-flags
     65   '("--ytdl-format=22,best"
     66     "--ytdl-raw-options=all-subs="
     67     "--speed=1.30")
     68   "The default flags to use for mpv when calling `plumb-stream'.
     69 You can choose different flags by passing a prefix argument to
     70 `plumb-stream'."
     71   :type '(repeat string)
     72   :group 'plumb)
     73 
     74 ;;;###autoload
     75 (defun plumb-stream (url &optional flags)
     76   "Plays video with mpv, provided URL is supported by youtube-dl.
     77 Optional argument FLAGS sets mpv flags; interactively, a prefix
     78 arg prompts for these flags."
     79   (interactive (list
     80                 (plumb-get-url "Stream video: ")
     81 		(when current-prefix-arg
     82 		  (read-string "mpv flags: "))))
     83   (let ((flags
     84 	 (if (stringp flags)
     85 	     (split-string flags " ")
     86 	   plumb-mpv-default-flags)))
     87     (eval
     88      `(start-process "mpv stream" ,(format " *mpv stream %s*" url)
     89 		     "mpv"
     90 		     ,@flags
     91 		     ,url)))
     92   (message "%s is being streamed" url))
     93 
     94 ;;;###autoload
     95 (defun plumb-download-video (url &optional directory)
     96   "Download the video of URL using youtube-dl.
     97 With prefix arg DIRECTORY, specify a download directory."
     98   (interactive (list
     99 		(plumb-get-url "Download video: ")
    100 		(when current-prefix-arg
    101 		  (read-directory-name "Download video where? "
    102 				       plumb-video-directory))))
    103   (let ((default-directory (or directory plumb-video-directory)))
    104     (start-process "youtube-dl download" " *youtube-dl download*"
    105 		   "youtube-dl"
    106 		   "--all-subs"
    107 		   "--format=22,best"
    108 		   "--add-metadata"
    109 		   "--output=%(title)s.%(ext)s"
    110 		   url))
    111   (message "%s downloaded in %s" url (or directory plumb-video-directory)))
    112 
    113 ;;;###autoload
    114 (defun plumb-audio (url &optional directory)
    115   "Downloads the audio of URL using youtube-dl.
    116 With prefix arg DIRECTORY, specify a download directory."
    117   (interactive (list
    118 		(plumb-get-url "Download audio: ")
    119 		(when current-prefix-arg
    120 		  (read-directory-name "Download audio where? "
    121 				       plumb-audio-directory))))
    122   (let ((default-directory (or directory plumb-audio-directory)))
    123     (start-process "youtube-dl audio" " *youtube-dl audio*"
    124 		   "youtube-dl"
    125 		   "--extract-audio"
    126 		   "--add-metadata"
    127 		   "--output=%(title)s.%(ext)s"
    128 		   url))
    129   (message "%s downloaded in %s" url (or directory plumb-audio-directory)))
    130 
    131 (defun plumb-save-to-register (url)
    132   "Copies URL into a register."
    133   (set-register
    134    (register-read-with-preview "Copy URL to register: ")
    135    url))
    136 
    137 (defun plumb-download-and-view (url &optional directory)
    138   "Download URL in either DIRECTORY or ~/Downloads, and then open it.
    139 Used by `plumb-image' and `plumb-pdf'."
    140   (let* ((file (expand-file-name
    141 		(file-name-nondirectory url)
    142 		(or directory "~/Downloads"))))
    143     (url-retrieve url
    144 		  (lambda (_status)
    145 		    (goto-char (point-min))
    146 		    (re-search-forward "\r?\n\r?\n")
    147 		    (write-region (point) (point-max) file)
    148 		    (find-file file)))
    149     file))
    150 
    151 (defun plumb-plain (url)
    152   "Download and open URL directly.  This should work with any
    153   filetype in `auto-mode-alist'."
    154   (plumb-download-and-view url))
    155 
    156 (defun plumb-image (url)
    157   "View URL as an image within Emacs."
    158   (plumb-download-and-view url plumb-image-directory))
    159 
    160 (defun plumb-pdf (url)
    161   "View URL as a pdf within Emacs."
    162   (plumb-download-and-view url plumb-pdf-directory))
    163 
    164 (defun plumb-view-as-org (url)
    165   "View URL in org-mode.  Requires `org-web-tools'."
    166   (unless (fboundp 'org-web-tools-read-url-as-org)
    167     (user-error "The package `org-web-tools' is not installed"))
    168   (org-web-tools-read-url-as-org url))
    169 
    170 (defun plumb-read (prompt)
    171   "Reads input for `plumb'"
    172   (completing-read (concat prompt " : ")
    173                    '("Save to register"
    174                      "eww"
    175                      "external browser"
    176                      "View as image"
    177                      "Stream"
    178 		     "View in org-mode"
    179 		     "Download and open"
    180 		     "Download video"
    181                      "Download audio"
    182                      "View as pdf")))
    183 
    184 (defun plumb-get-url (&optional prompt)
    185   "Get URL at point or from minibuffer"
    186   (or (get-char-property (point) 'bug-reference-url)
    187       (shr-url-at-point nil)
    188       (thing-at-point 'url t)
    189       (and (derived-mode-p 'org-mode)
    190 	   (eq 'org-link (get-text-property (point) 'face))
    191 	   (let ((link
    192 		  (replace-regexp-in-string
    193 		   "\\`LINK: " ""
    194 		   (get-text-property (point) 'help-echo))))
    195 	     (when (string-match-p (regexp-opt thing-at-point-uri-schemes) link)
    196 	       link)))
    197       (read-string (or prompt
    198 		       "URL: "))))
    199 
    200 ;;;###autoload
    201 (defun plumb (url)
    202   "Select a way to use a URL"
    203   (interactive (list (plumb-get-url)))
    204   (let ((choice (plumb-read url)))
    205     (pcase choice
    206       ("Save to register"
    207        (plumb-save-to-register url))
    208       ("eww"
    209        (eww url))
    210       ("external browser"
    211        (eww-browse-with-external-browser url))
    212       ("View as image"
    213        (plumb-image url))
    214       ("View as pdf"
    215        (plumb-pdf url))
    216       ("View in org-mode"
    217        (plumb-view-as-org url))
    218       ("Download and open"
    219        (plumb-plain url))
    220       ("Stream"
    221        (plumb-stream url))
    222       ("Download video"
    223        (plumb-download-video url))
    224       ("Download audio"
    225        (plumb-audio url)))))
    226 
    227 (provide 'plumb)
    228 ;;; plumb.el ends here