summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.org31
-rw-r--r--README8
-rw-r--r--README.md94
-rw-r--r--yeetube-mpv.el19
-rw-r--r--yeetube.el109
5 files changed, 142 insertions, 119 deletions
diff --git a/CONTRIBUTING.org b/CONTRIBUTING.org
new file mode 100644
index 0000000..6454f5d
--- /dev/null
+++ b/CONTRIBUTING.org
@@ -0,0 +1,31 @@
+#+title: Contributing | YeeTube
+#+author: Thanos Apollo
+
+
+* Sources
++ [[https://git.thanosapollo.org/yeetube][Upstream]]
+
+* How To Contribute
+
+Before starting to work on any big feature, that is not mentioned on
+the [[Task List][Task List]], I recommend you to send me an email first.
+
+** How to submit a PR?
++ Feel free to send me a patch, here's how to create one
+
+#+begin_src bash
+$ git clone https://git.thanosapollo.com/<repo>.git && cd <repo>
+$ emacs something
+$ git add something
+$ git commit -m "Fix something"
+$ git format-patch HEAD^1
+0001-Fix-something.patch
+#+end_src
+
+/You can find my email on the git log/
+
+
+* Tasks
+** DONE Add sorting for tabulated list views/date/title/duration
+CLOSED: [2024-02-10 Sat 11:38]
++ With the help of Boruch Baum <[email protected]>
diff --git a/README b/README
new file mode 100644
index 0000000..2222516
--- /dev/null
+++ b/README
@@ -0,0 +1,8 @@
+
+YeeTube
+========
+YouTube Front End for GNU Emacs
+
+
+Project's Page: <https://thanosapollo.org/projects/yeetube>
+Upstream: <https://git.thanosapollo.org/yeetube>
diff --git a/README.md b/README.md
deleted file mode 100644
index e92df6e..0000000
--- a/README.md
+++ /dev/null
@@ -1,94 +0,0 @@
-[![MELPA](https://melpa.org/packages/yeetube-badge.svg)](https://melpa.org/#/yeetube)
-
-# YeeTube
-
-![yeetube showcase](/showcase/example.gif?raw=true "Showcase Yeetube")
-## About
-
-This package provides the ability to scrape YouTube, with the results
-displayed in a proced-like buffer.
-
-
-Package functionality includes:
-
-- Query YouTube
-- Play video url *by default using mpv*
-- Bookmark/Save video url
-- Download video *using yt-dlp*
-- A minimal yt-dlp front-end, *which is independent of the rest
- YouTube functionality*.
-
-*This package does not use Invidious or YouTube's API, just "parses"
-html & json.*
-
-
-## Installation
-This package is available via [MELPA](https://melpa.org/#/yeetube)
-
-### Straight.el
-
-``` emacs-lisp
-(straight-use-package
- '(yeetube :type git
- :host nil
- :repo "https://git.thanosapollo.org/yeetube"))
-```
-
-
-### Manual
-``` shell
-$ git clone https://git.thanosapollo.org/yeetube
-```
-
-*Add this to your emacs configuration:*
-
-``` emacs-lisp
- (add-to-list 'load-path "/path/to/yeetube")
- (load-file "~/path/to/yeetube.el")
- (require 'yeetube)
-```
-
-### Dependencies
-- [mpv](https://mpv.io/): default multimedia player
-- [yt-dlp](https://github.com/yt-dlp/yt-dlp): download functionality
-
-*Debian/Ubuntu*
-``` shell
-$ sudo apt install mpv yt-dlp
-```
-
-## Configuration
-### Media Player
-By default `yeetube-player` is set to `yeetube-mpv-play`, you can
-use [mpv.el](https://github.com/kljohann/mpv.el),
-[GNU/Emms](https://www.gnu.org/software/emms/) or other similar
-packages like so:
-
-``` emacs-lisp
-(setf yeetube-player #'emms-play-url)
-```
-
-Make sure that the media player of your choice can directly play
-youtube urls.
-
-### Apply Filters
-
-To filter the search results based on a specific criterion, you can
-modify the `yeetube-filter` value to your preferred option.
-
-For example:
-
-```emacs-lisp
-(setf yeetube-filter "Views")
-```
-
-This will filter & sort the search results according to the number of views.
-
-
-### FAQ
-#### Feature request: display thumbnails
-Formatting images in a text buffer is not something that I found easy
-or fun to do. Feel free to submit a patch if you manage to make an
-appealing version of it
-
-
diff --git a/yeetube-mpv.el b/yeetube-mpv.el
index 474b88f..2c925a4 100644
--- a/yeetube-mpv.el
+++ b/yeetube-mpv.el
@@ -40,6 +40,17 @@
(defvar yeetube-mpv-torsocks (executable-find "torsocks")
"Path to torsocks executable.")
+(defvar yeetube-mpv-video-quality "720"
+ "Video resolution/quality
+
+Accepted values include: 1080, 720, 480, 360, 240, 144")
+
+(defun yeetube-mpv-change-video-quality ()
+ (interactive)
+ (let ((new-value (completing-read (format "Set video quality (current value %s):" yeetube-mpv-video-quality)
+ '("1080" "720" "480" "360" "240" "144") nil t)))
+ (setf yeetube-mpv-video-quality new-value)))
+
(defun yeetube-mpv-toggle-torsocks ()
"Toggle torsocks."
(interactive)
@@ -67,6 +78,10 @@
(start-process-shell-command
"yeetube" nil command))))
+(defun yeetube-mpv-ytdl-format-video-quality (resolution)
+ "Return shell quoted argument for ytdlp with RESOLUTION."
+ (shell-quote-argument (format "bestvideo[height<=?%s]+bestaudio/best" resolution)))
+
(defun yeetube-mpv-play (input)
"Start yeetube process to play INPUT using mpv.
@@ -75,7 +90,9 @@ to play local files."
(yeetube-mpv-process
(concat (when yeetube-mpv-enable-torsocks
(concat yeetube-mpv-torsocks " "))
- yeetube-mpv-path " "
+ yeetube-mpv-path " --ytdl-format="
+ (yeetube-mpv-ytdl-format-video-quality yeetube-mpv-video-quality)
+ " "
(shell-quote-argument input)
(when yeetube-mpv-disable-video " --no-video")))
(message (if yeetube-mpv-enable-torsocks
diff --git a/yeetube.el b/yeetube.el
index 0ec9d97..ff6c16d 100644
--- a/yeetube.el
+++ b/yeetube.el
@@ -4,9 +4,8 @@
;; Author: Thanos Apollo <[email protected]>
;; Keywords: extensions youtube videos
-;; URL: https://git.thanosapollo.org/yeetube
-;; Version: 2.1.1
-
+;; URL: https://thanosapollo.org/projects/yeetube/
+;; Version: 2.1.2
;; Package-Requires: ((emacs "27.2") (compat "29.1.4.2"))
@@ -83,7 +82,19 @@ Valid options include:
:type '(radio (const "Relevance")
(const "Date")
(const "Views")
- (const "Rating"))
+ (const "Rating")))
+
+(defcustom yeetube-default-sort-column nil
+ "Which column to sort the search results table."
+ :type '(radio (const "Title")
+ (const "Views")
+ (const "Duration")
+ (const "Channel"))
+ :group 'yeetube)
+
+(defcustom yeetube-default-sort-ascending nil
+ "Whether to sort the search results in ascending order."
+ :type 'boolean
:group 'yeetube)
(defgroup yeetube-faces nil
@@ -117,6 +128,11 @@ Valid options include:
"Face used for video channel name."
:group 'yeetube-faces)
+(defface yeetube-face-date
+ '((t :inherit font-lock-doc-face))
+ "Face used for published date."
+ :group 'yeetube-faces)
+
(defvar yeetube-invidious-instances
'("vid.puffyan.us"
"invidious.flokinet.to"
@@ -264,10 +280,17 @@ This is used to download thumbnails from `yeetube-content', within
nil 0)))))
(defvar yeetube-filter-code-alist
- '(("Relevance" . "CAASAhAB")
+ '(("Relevance" . "EgIQAQ%253D%253D")
("Date" . "CAISAhAB")
("Views" . "CAMSAhAB")
- ("Rating" . "CAESAhAB")))
+ ("Rating" . "CAESAhAB"))
+ "Filter codes.")
+
+(defvar yeetube-request-headers
+ '(("Accept-Language" . "Accept-Language: en-US,en;q=0.9")
+ ("Accept" . "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
+ ("User-Agent" . "Mozilla/5.0 (Windows NT 10.0; rv:122.0) Gecko/20100101 Firefox/122.0"))
+ "HTTP Request extra headers")
(defun yeetube-get-filter-code (filter)
"Get filter code for sorting search results."
@@ -277,20 +300,21 @@ This is used to download thumbnails from `yeetube-content', within
(defun yeetube-search (query)
"Search for QUERY."
(interactive "sYeetube Search: ")
- (with-current-buffer
- (url-retrieve-synchronously
- (concat "https://youtube.com/search?q="
- (replace-regexp-in-string " " "+" query)
- ;; Filter parameter to remove live videos.
- "&sp="
- (yeetube-get-filter-code yeetube-filter))
- 'silent 'inhibit-cookies 30)
- (decode-coding-region (point-min) (point-max) 'utf-8)
- (goto-char (point-min))
- (toggle-enable-multibyte-characters)
- (yeetube-get-content))
- ;; (yeetube-get-thumbnails yeetube-content) ;; download thumbnails
- ;; unfortunately we can't use images them with tabulated list
+ (let ((url-request-extra-headers yeetube-request-headers))
+ (with-current-buffer
+ (url-retrieve-synchronously
+ (concat "https://youtube.com/search?q="
+ (replace-regexp-in-string " " "+" query)
+ ;; Filter parameter to remove live videos.
+ "&sp="
+ (yeetube-get-filter-code yeetube-filter))
+ 'silent 'inhibit-cookies 30)
+ (decode-coding-region (point-min) (point-max) 'utf-8)
+ (goto-char (point-min))
+ (toggle-enable-multibyte-characters)
+ (yeetube-get-content)))
+ ;; (yeetube-get-thumbnails yeetube-content) ;; download thumbnails
+ ;; unfortunately we can't use images them with tabulated list
(with-current-buffer
(switch-to-buffer (get-buffer-create (concat "*yeetube*")))
(yeetube-mode)))
@@ -348,13 +372,15 @@ SUBSTRING-END is the end of the string to return, interger."
(view-count (yeetube-scrape-item :item "viewcounttext" :item-end " " :substring-end 0))
(video-duration (yeetube-scrape-item :item "lengthtext" :item-end "}," :substring-end 3))
(channel (yeetube-scrape-item :item "longbylinetext" :item-end "," :substring-end 2))
- (thumbnail (yeetube-scrape-item :item "thumbnail" :item-start "url" :item-end ",\"" :substring-end 5)))
+ (thumbnail (yeetube-scrape-item :item "thumbnail" :item-start "url" :item-end ",\"" :substring-end 5))
+ (date (yeetube-scrape-item :item "publishedtimetext" :item-end ",\"" :substring-end 4)))
(push (list :title title
:videoid videoid
:view-count (yeetube-view-count-format view-count)
:duration video-duration
:channel channel
- :thumbnail thumbnail)
+ :thumbnail thumbnail
+ :date (replace-regexp-in-string "Streamed " "" date))
yeetube-content))))))
(add-variable-watcher 'yeetube-saved-videos #'yeetube-update-saved-videos-list)
@@ -472,12 +498,45 @@ FIELDS-FACE-PAIRS is a list of fields and faces."
"r" #'yeetube-replay
"t" #'yeetube-view-thumbnail
"T" #'yeetube-mpv-toggle-torsocks
+ "C-q" #'yeetube-mpv-change-video-quality
"q" #'quit-window)
+(defun yeetube--sort-views (a b)
+ "PREDICATE for function 'sort'.
+Used by variable 'tabulated-list-format' to sort the \"Views\"
+column."
+ (< (string-to-number (replace-regexp-in-string "," "" (aref (cadr a) 1)))
+ (string-to-number (replace-regexp-in-string "," "" (aref (cadr b) 1)))))
+
+(defun yeetube--sort-duration (a b)
+ "PREDICATE for function 'sort'.
+Used by variable 'tabulated-list-format' to sort the \"Duration\"
+column."
+ (< (string-to-number (replace-regexp-in-string ":" "" (aref (cadr a) 2)))
+ (string-to-number (replace-regexp-in-string ":" "" (aref (cadr b) 2)))))
+
+(defun yeetube--sort-date (a b)
+ "PREDICATE for function 'sort'.
+Used by variable 'tabulated-list-format' to sort the \"Date\"
+column."
+ (let* ((intervals '("second" "minute" "hour" "day" "week" "month" "year"))
+ (split-a (split-string (replace-regexp-in-string "s" "" (aref (cadr a) 3))))
+ (split-b (split-string (replace-regexp-in-string "s" "" (aref (cadr b) 3))))
+ (units-a (length (member (nth 1 split-a) intervals)))
+ (units-b (length (member (nth 1 split-b) intervals))))
+ (if (= units-a units-b)
+ (< (string-to-number (nth 0 split-a)) (string-to-number (nth 0 split-b)))
+ (> units-a units-b))))
+
(define-derived-mode yeetube-mode tabulated-list-mode "Yeetube"
"Yeetube mode."
:keymap yeetube-mode-map
- (setf tabulated-list-format [("Title" 60 t) ("Views" 12 t) ("Duration" 12 t) ("Channel" 12 t)]
+ (setf tabulated-list-format
+ [("Title" 60 t)
+ ("Views" 11 yeetube--sort-views)
+ ("Duration" 9 yeetube--sort-duration)
+ ("Date" 13 yeetube--sort-date)
+ ("Channel" 8 t)]
tabulated-list-entries
(cl-map 'list
(lambda (content)
@@ -486,9 +545,11 @@ FIELDS-FACE-PAIRS is a list of fields and faces."
:title 'yeetube-face-title
:view-count 'yeetube-face-view-count
:duration 'yeetube-face-duration
+ :date 'yeetube-face-date
:channel 'yeetube-face-channel)))
(reverse yeetube-content))
- tabulated-list-sort-key nil)
+ tabulated-list-sort-key (cons yeetube-default-sort-column
+ yeetube-default-sort-ascending))
(display-line-numbers-mode 0)
(tabulated-list-init-header)
(tabulated-list-print))