collect supports adding files and webpage content

This commit is contained in:
Levi Neely 2024-09-17 14:50:56 +02:00
parent 726734b04f
commit 277d15d4bd
1 changed files with 135 additions and 43 deletions

View File

@ -10,8 +10,24 @@
;;; collect/store-path is a variable that stores a string defining the path to the directory under which collections are stored.
(require 'url)
(require 'time-date)
(defvar collect/store-path "~/collections")
(defvar collect/supported-mime-types
'("text/plain"
"text/html"
"text/css"
"text/javascript"
"application/json"
"application/xml"
"text/xml"
"text/markdown"
"text/csv")
"List of MIME types supported for collection.")
(defun collect/delete-collection-internal (collection-name)
"Delete an existing collection, moving its contents (except .collection-metadata) into the no-name collection."
(let ((source-dir (expand-file-name collection-name collect/store-path))
@ -33,36 +49,40 @@
(message "Collection '%s' deleted and contents moved to 'no-name' collection." collection-name))
(error "Collection '%s' does not exist" collection-name))))
(defun collect/delete-collection ()
"Interactively delete an existing collection."
(interactive)
(let* ((collections (collect/get-collections))
(choice (completing-read "Select collection to delete: " (mapcar #'car collections) nil t))
(dir-to-delete (cdr (assoc choice collections))))
(when dir-to-delete
(collect/delete-collection-internal (file-name-nondirectory dir-to-delete)))))
(defun collect/create-collection ()
"Interactively create a new collection."
(interactive)
(let ((collection-name (read-string "Enter collection name: ")))
(collect/create-collection-internal collection-name)))
(defun collect/delete-collection ()
"Interactively delete an existing collection."
(interactive)
(let* ((all-files (directory-files collect/store-path t "^[^.]"))
(collections (cl-remove-if
(lambda (dir)
(or (not (file-directory-p dir))
(string= (file-name-nondirectory dir) "no-name")))
all-files))
(collection-names
(mapcar (lambda (dir)
(let ((metadata-file (expand-file-name ".collection-metadata" dir)))
(if (file-exists-p metadata-file)
(with-temp-buffer
(insert-file-contents metadata-file)
(if (re-search-forward "^name: \\(.*\\)$" nil t)
(match-string 1)
(file-name-nondirectory dir)))
(file-name-nondirectory dir))))
collections))
(choice (completing-read "Select collection to delete: " collection-names nil t))
(dir-to-delete (nth (cl-position choice collection-names :test 'string=) collections)))
(when dir-to-delete
(collect/delete-collection-internal (file-name-nondirectory dir-to-delete)))))
(defun collect/create-collection-internal (collection-name)
"Create a new collection with the given name."
(let* ((unix-path (replace-regexp-in-string "[^[:alnum:]_-]" "-"
(downcase (string-trim collection-name))))
(full-path (expand-file-name unix-path collect/store-path))
(metadata-file (expand-file-name ".collection-metadata" full-path))
(current-time (format-time-string "%Y-%m-%d %H:%M:%S")))
(cond
((string-empty-p unix-path)
(error "Collection name cannot be empty"))
((file-exists-p full-path)
(error "Collection '%s' already exists" collection-name))
(t
(make-directory full-path t)
(with-temp-file metadata-file
(insert (format "name: %s\n" collection-name)
(format "created: %s\n" current-time)
(format "updated: %s\n" current-time)))
(message "Collection '%s' created successfully with metadata." collection-name)))))
(defun collect/rename-collection-internal (old-name new-name)
"Rename collection from OLD-NAME to NEW-NAME."
@ -101,27 +121,11 @@
(defun collect/rename-collection ()
"Interactively rename an existing collection."
(interactive)
(let* ((all-files (directory-files collect/store-path t "^[^.]"))
(collections (cl-remove-if
(lambda (dir)
(or (not (file-directory-p dir))
(string= (file-name-nondirectory dir) "no-name")))
all-files))
(collection-names
(mapcar (lambda (dir)
(let ((metadata-file (expand-file-name ".collection-metadata" dir)))
(if (file-exists-p metadata-file)
(with-temp-buffer
(insert-file-contents metadata-file)
(if (re-search-forward "^name: \\(.*\\)$" nil t)
(match-string 1)
(file-name-nondirectory dir)))
(file-name-nondirectory dir))))
collections))
(old-name (completing-read "Select collection to rename: " collection-names nil t))
(let* ((collections (collect/get-collections))
(old-name (completing-read "Select collection to rename: " (mapcar #'car collections) nil t))
(new-name (read-string (format "Enter new name for collection '%s': " old-name))))
(when (and old-name new-name)
(let ((dir-to-rename (nth (cl-position old-name collection-names :test 'string=) collections)))
(let ((dir-to-rename (cdr (assoc old-name collections))))
(when dir-to-rename
(collect/rename-collection-internal (file-name-nondirectory dir-to-rename) new-name))))))
@ -159,5 +163,93 @@
(file-name-nondirectory file-to-add)
selected-collection)))))
(defun collect/add-webpage-to-collection ()
"Add a webpage to a specified collection."
(interactive)
(let* ((url (read-string "Enter URL to add: "))
(all-files (directory-files collect/store-path t "^[^.]"))
(collections (cl-remove-if
(lambda (dir)
(or (not (file-directory-p dir))
(string= (file-name-nondirectory dir) "no-name")))
all-files))
(collection-names
(mapcar (lambda (dir)
(let ((metadata-file (expand-file-name ".collection-metadata" dir)))
(if (file-exists-p metadata-file)
(with-temp-buffer
(insert-file-contents metadata-file)
(if (re-search-forward "^name: \\(.*\\)$" nil t)
(match-string 1)
(file-name-nondirectory dir)))
(file-name-nondirectory dir))))
collections))
(selected-collection (completing-read "Select collection to add to: " collection-names nil t))
(target-dir (nth (cl-position selected-collection collection-names :test 'string=) collections)))
(when (and url target-dir)
(plz 'get url
:as 'response
:then (lambda (response)
(collect/process-webpage-response url response target-dir selected-collection))
:else (lambda (error)
(message "Error fetching webpage: %s" error))))))
(defun collect/get-collections ()
"Get a list of collections with their names and directories."
(let ((all-dirs (directory-files collect/store-path t "^[^.]")))
(cl-remove-if #'null
(mapcar (lambda (dir)
(when (file-directory-p dir)
(let* ((metadata-file (expand-file-name ".collection-metadata" dir))
(name (collect/get-collection-name metadata-file)))
(when name
(cons name dir)))))
all-dirs))))
(defun collect/get-collection-name (metadata-file)
"Get the collection name from the metadata file."
(when (file-exists-p metadata-file)
(with-temp-buffer
(insert-file-contents metadata-file)
(goto-char (point-min))
(when (re-search-forward "^name: \\(.+\\)$" nil t)
(match-string 1)))))
(defun collect/add-webpage-to-collection ()
"Add a webpage to a specified collection."
(interactive)
(let* ((url (read-string "Enter URL to add: "))
(collections (collect/get-collections))
(selected-collection (completing-read "Select collection to add to: " (mapcar #'car collections) nil t))
(target-dir (cdr (assoc selected-collection collections)))
(filename (collect/generate-filename url))
(target-file (expand-file-name filename target-dir)))
(when (and url (file-directory-p target-dir))
(url-retrieve url
(lambda (status target-file filename collection-name)
(if (plist-get status :error)
(message "Error fetching webpage: %s" (plist-get status :error))
(goto-char (point-min))
(re-search-forward "\n\n")
(write-region (point) (point-max) target-file)
(message "Webpage '%s' added to collection '%s'." filename collection-name)))
(list target-file filename selected-collection)))))
(defun collect/generate-filename (url)
"Generate a filename for the given URL."
(let* ((timestamp (format-time-string "%Y%m%dT%H%M%S"))
(parsed-url (url-generic-parse-url url))
(host (url-host parsed-url))
(path (url-filename parsed-url))
(path-without-schema (replace-regexp-in-string "^/+" "" path))
(sanitized-path (replace-regexp-in-string "[^a-zA-Z0-9._-]" "_" path-without-schema))
(full-path (concat host "_" sanitized-path))
(extension (if (string-match "\\.[^.]+$" full-path)
(match-string 0 full-path)
".html")))
(concat timestamp "_" (file-name-sans-extension full-path) extension)))
(provide 'module-collect)