diff options
-rw-r--r-- | yeetube-buffer.el | 192 | ||||
-rw-r--r-- | yeetube.el | 109 |
2 files changed, 80 insertions, 221 deletions
diff --git a/yeetube-buffer.el b/yeetube-buffer.el deleted file mode 100644 index 379a8eb..0000000 --- a/yeetube-buffer.el +++ /dev/null @@ -1,192 +0,0 @@ -;;; yeetube-buffer.el --- Yeetube Buffer -*- lexical-binding: t; -*- - -;; Copyright (C) 2023 Thanos Apollo - -;; Author: Thanos Apollo <[email protected]> -;; Keywords: extensions youtube videos -;; URL: https://git.thanosapollo.org/yeetube - -;; 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: - -;; This package is an extension for yeetube, to create a custom -;; *yeetube* buffer. - -;;; Code: - -(require 'cl-lib) - -(defcustom yeetube-buffer-display-emojis nil - "Display video title's emojis. - -Emojis cause formatting issues, this should be off by default." - :type 'boolean - :group 'yeetube) - -(defgroup yeetube-buffer-faces nil - "Faces used by yeetube." - :group 'yeetube - :tag "Yeetube Faces" - :prefix 'yeetube-face) - -(defface yeetube-buffer-face-header-query - '((t :inherit font-lock-function-name-face)) - "Face used for the video published date." - :group 'yeetube-buffer-faces) - -(defface yeetube-buffer-face-duration - '((t :inherit font-lock-string-face)) - "Face used for the video duration." - :group 'yeetube-buffer-faces) - -(defface yeetube-buffer-face-view-count - '((t :inherit font-lock-keyword-face)) - "Face used for the video view count." - :group 'yeetube-buffer-faces) - -(defface yeetube-buffer-face-title - '((t :inherit font-lock-variable-use-face)) - "Face used for video title." - :group 'yeetube-buffer-faces) - -(defface yeetube-buffer-face-channel - '((t :inherit font-lock-function-call-face)) - "Face used for video channel name." - :group 'yeetube-buffer-faces) - -(defun yeetube-buffer-strip-emojis (str) - "Remove characters which are part of the `emoji' script from STR." - (cl-remove-if (lambda (c) - (equal (aref char-script-table c) 'emoji)) - str)) - -(defun yeetube-buffer-fix-view-count (view-count) - "Fix VIEW-COUNT display issues." - (replace-regexp-in-string "[^0-9]" "" view-count)) - -(defun yeetube-buffer-view-count-add-commas (string) - "Add commas for STRING." - (let ((result "") - (len (length string))) - (dotimes (i len) - (setf result (concat (substring string (- len i 1) (- len i)) result)) - (when (and (> (- len (1+ i)) 0) - (= (% (1+ i) 3) 0)) - (setf result (concat "," result)))) - result)) - -;;; Formatting inspired from ytel -(defun yeetube-buffer--format-header-title (query) - "Format header for QUERY." - (let* ((n (string-width query)) - (extra-chars (- n 53)) - (formatted-string - (if (<= extra-chars 0) - (concat query - (make-string (abs extra-chars) ?\ ) - " ") - (concat (seq-subseq query 0 50) - "... " )))) - (propertize formatted-string 'face 'yeetube-buffer-face-header-query))) - -(defun yeetube-buffer--format-title (title) - "Format a video TITLE to be inserted in the *yeetube* buffer." - (let* ((n (string-width title)) - (extra-chars (- n 60)) - (formatted-string - (if (<= extra-chars 0) - (concat title - (make-string (abs extra-chars) ?\ ) - " ") - (concat (seq-subseq title 0 57) - "... " )))) - (propertize formatted-string 'face 'yeetube-buffer-face-title))) - -(defun yeetube-buffer--format-view-count (view-count) - "Format a video VIEW-COUNT to be inserted in the *yeetube* buffer." - (let* ((n (string-width view-count)) - (extra-chars (- n 13)) - (formatted-string - (if (<= extra-chars 0) - (concat view-count - (make-string (abs extra-chars) ?\ ) - " ") - (concat (seq-subseq view-count 0 10) - "...")))) - (propertize formatted-string 'face 'yeetube-buffer-face-view-count))) - -(defun yeetube-buffer--format-video-duration (video-duration) - "Format a video VIDEO-DURATION to be inserted in the *yeetube* buffer." - (let* ((n (string-width video-duration)) - (extra-chars (- n 13)) - (formatted-string (if (<= extra-chars 0) - (concat video-duration - (make-string (abs extra-chars) ?\ ) - " ") - (concat (seq-subseq video-duration 0 10) - "...")))) - (propertize formatted-string 'face 'yeetube-buffer-face-duration))) - -(defun yeetube-buffer--format-channel (channel) - "Format a video CHANNEL to be inserted in the *yeetube* buffer." - (let* ((n (string-width channel)) - (extra-chars (- n 15)) - (formatted-string - (if (<= extra-chars 0) - (concat channel - (make-string (abs extra-chars) ?\ ) - " ") - (concat (seq-subseq channel 0 11) - "... " )))) - (propertize formatted-string 'face 'yeetube-buffer-face-channel))) - -(defun yeetube-buffer--format-header (query) - "Render header for *yeetube* buffer for QUERY." - (setf header-line-format - (concat - "Search: " (yeetube-buffer--format-header-title query) - (yeetube-buffer--format-view-count "Views") - (yeetube-buffer--format-video-duration "Duration") - (yeetube-buffer--format-channel "Channel")))) - -(defun yeetube-buffer-insert-content (content) - "Insert formatted CONTENT." - (insert - (concat - (yeetube-buffer--format-title (cl-getf content :title)) - (yeetube-buffer--format-view-count (yeetube-buffer-view-count-add-commas - (yeetube-buffer-fix-view-count - (cl-getf content :view-count)))) - (yeetube-buffer--format-video-duration (cl-getf content :duration)) - (yeetube-buffer--format-channel (cl-getf content :channel)) - "\n"))) - -;;;###autoload -(defun yeetube-buffer-create (query content buffer-mode) - "Create *yeetube* buffer with BUFFER-MODE for search QUERY, displaying CONTENT." - (with-current-buffer - (switch-to-buffer (get-buffer-create "*yeetube*")) - (funcall buffer-mode) - (setf buffer-read-only nil) - (erase-buffer) - (yeetube-buffer--format-header query) - (cl-loop for result in (reverse content) - do (yeetube-buffer-insert-content result)) - (delete-char -1) - (goto-char (point-min)) - (setf buffer-read-only t))) - -(provide 'yeetube-buffer) -;;; yeetube-buffer.el ends here @@ -40,8 +40,8 @@ (require 'compat) (require 'url) +(require 'tabulated-list) (require 'cl-lib) -(require 'yeetube-buffer) (require 'yeetube-mpv) (defgroup yeetube nil @@ -51,7 +51,7 @@ (defcustom yeetube-results-limit 20 "Define a limit for search results." - :type 'natnump + :type 'number :group 'yeetube) (defcustom yeetube-player #'yeetube-mpv-play @@ -73,6 +73,37 @@ Example Usage: :type 'string :group 'yeetube) +(defgroup yeetube-faces nil + "Faces used by yeetube." + :group 'yeetube + :tag "Yeetube Faces" + :prefix 'yeetube-face) + +(defface yeetube-face-header-query + '((t :inherit font-lock-function-name-face)) + "Face used for the video published date." + :group 'yeetube-faces) + +(defface yeetube-face-duration + '((t :inherit font-lock-string-face)) + "Face used for the video duration." + :group 'yeetube-faces) + +(defface yeetube-face-view-count + '((t :inherit font-lock-keyword-face)) + "Face used for the video view count." + :group 'yeetube-faces) + +(defface yeetube-face-title + '((t :inherit font-lock-variable-use-face)) + "Face used for video title." + :group 'yeetube-faces) + +(defface yeetube-face-channel + '((t :inherit font-lock-function-call-face)) + "Face used for video channel name." + :group 'yeetube-faces) + (defvar yeetube-invidious-instances '("vid.puffyan.us" "invidious.flokinet.to" @@ -110,9 +141,7 @@ Keywords: - :channel" (unless (keywordp keyword) (error "Value `%s' is not a keyword" keyword)) - (let ((video-info - (cl-getf (nth (- (line-number-at-pos) 1) (reverse yeetube-content)) keyword))) - video-info)) + (cl-getf (tabulated-list-get-id) keyword)) (defun yeetube-get-url () "Get video url." @@ -217,8 +246,10 @@ WHERE indicates where in the buffer the update should happen." (decode-coding-region (point-min) (point-max) 'utf-8) (goto-char (point-min)) (toggle-enable-multibyte-characters) - (yeetube-get-content) - (yeetube-buffer-create query yeetube-content 'yeetube-mode))) + (yeetube-get-content)) + (with-current-buffer + (switch-to-buffer (get-buffer-create (concat "*yeetube*"))) + (yeetube-mode))) ;;;###autoload (defun yeetube-browse-url () @@ -248,16 +279,17 @@ then for item." ("\\\\" . "")) "Unicode character replacements.") -;; Usually titles from youtube get messed up, -;; This should fix some of the common issues. -(defun yeetube---fix-title (title) - "Adjust TITLE." - (mapc (lambda (replacement) - (setf title (replace-regexp-in-string (car replacement) (cdr replacement) title))) - yeetube--title-replacements) - (if yeetube-buffer-display-emojis - title - (yeetube-buffer-strip-emojis title))) +(defun yeetube-view-count-format (string) + "Add commas for STRING." + (let* ((string (replace-regexp-in-string "[^0-9]" "" string)) + (len (length string)) + (result "")) + (cl-loop for i from 0 to (1- len) + do (setf result (concat (substring string (- len i 1) (- len i)) result)) + if (and (> (- len (1+ i)) 0) + (= (% (1+ i) 3) 0)) + do (setf result (concat "," result))) + result)) (defun yeetube-get-content () "Get content from youtube." @@ -269,9 +301,8 @@ then for item." (- (search-forward ",") 2)))) (unless (member videoid (car yeetube-content)) (yeetube-get-item "title") ;; Video Title - (let ((title (yeetube---fix-title - (buffer-substring (+ (point) 3) - (- (search-forward ",\"") 5))))) + (let ((title (buffer-substring (+ (point) 3) + (- (search-forward ",\"") 5)))) (unless (member title (car yeetube-content)) (yeetube-get-item "viewcounttext") ;; View Count (let ((view-count (buffer-substring (+ (point) 3) @@ -284,7 +315,7 @@ then for item." (- (search-forward ",") 2)))) (push (list :title title :videoid videoid - :view-count view-count + :view-count (yeetube-view-count-format view-count) :duration video-duration :channel channel) yeetube-content)))))))))) @@ -371,16 +402,24 @@ prompt blank to keep the default name." (setf download-counter (1+ download-counter)) (yeetube-download--ytdlp url name yeetube-download-audio-format))))) -;; Yeetube Mode +(defun yeetube-propertize-vector (content &rest fields-face-pairs) + "Create a vector with each item propertized with its corresponding face. +CONTENT is a list of strings. +FIELDS-FACE-PAIRS is a list of fields and faces." + (apply #'vector + (cl-loop for (field face) on fields-face-pairs by #'cddr + collect (propertize (cl-getf content field) 'face face)))) + +;; Yeetube Mode (defvar-keymap yeetube-mode-map :doc "Keymap for yeetube commands" "RET" #'yeetube-play "M-RET" #'yeetube-search "b" #'yeetube-browse-url "d" #'yeetube-download-video - "D" #'yeetube-change-download-directory - "a" #'yeetube-change-download-audio-format + "D" #'yeetube-download-change-directory + "a" #'yeetube-download-change-audio-format "p" #'yeetube-mpv-toggle-pause "v" #'yeetube-mpv-toggle-video "V" #'yeetube-mpv-toggle-no-video-flag @@ -389,13 +428,25 @@ prompt blank to keep the default name." "r" #'yeetube-replay "q" #'quit-window) -(define-derived-mode yeetube-mode special-mode "Yeetube" +(define-derived-mode yeetube-mode tabulated-list-mode "Yeetube" "Yeetube mode." - :interactive t - (abbrev-mode 0) + :keymap yeetube-mode-map + (setf tabulated-list-format [("Title" 60 t) ("Views" 12 t) ("Duration" 12 t) ("Channel" 12 t)] + tabulated-list-entries + (cl-map 'list + (lambda (content) + (list content + (yeetube-propertize-vector content + :title 'yeetube-face-title + :view-count 'yeetube-face-view-count + :duration 'yeetube-face-duration + :channel 'yeetube-face-channel))) + yeetube-content) + tabulated-list-sort-key (cons "Title" nil)) (display-line-numbers-mode 0) - :lighter " yeetube-mode" - :keymap yeetube-mode-map) + (tabulated-list-init-header) + (tabulated-list-print) + (hl-line-mode)) (provide 'yeetube) ;;; yeetube.el ends here |