Coder Social home page Coder Social logo

ytel's Introduction

ytel

ytel is an experimental YouTube "frontend" for Emacs. It's goal is to allow the user to collect the results of a YouTube search in an elfeed-like buffer and then manipulate them with Emacs Lisp. The gif below shows that ytel can be used to play videos in an external player, to learn how to emulate it refer to the usage section below.

This project was inspired by elfeed and Invidious (it does indeed use the Invidious APIs).

Installation

This project is on MELPA: you should be able to M-x package-install RET ytel. Another option is to clone this repository under your load-path.

Dependencies

While ytel does not depend on any Emacs package it does depend on curl so, if you happen not to have it, install it through your package manager (meme distros aside it is probably in your repos).

Usage

Once everything is loaded M-x ytel creates a new buffer and puts it in ytel-mode. This major mode has just a few bindings (for now):

key binding
n next-line
p previous-line
q ytel-quit
s ytel-search
> ytel-search-next-page
< ytel-search-previous-page

Pressing s will prompt for some search terms and populate the buffer once the results are available. One can access information about a video via the function ytel-get-current-video that returns the video at point. Videos returned by ytel-get-current-video are cl-structures so you can access their fields with the ytel-video-* functions. Currently videos have four fields:

field description
id the video's id
title the video's title
author name of the author of the video
authorId id of the channel that updated the video
length length of the video in seconds
views number of views
published date of publication (unix-style timestamp)

With this information we can implement a function to stream a video in mpv (provided you have youtube-dl installed) as follows:

(defun ytel-watch ()
    "Stream video at point in mpv."
    (interactive)
    (let* ((video (ytel-get-current-video))
     	   (id    (ytel-video-id video)))
      (start-process "ytel mpv" nil
		     "mpv"
		     (concat "https://www.youtube.com/watch?v=" id))
		     "--ytdl-format=bestvideo[height<=?720]+bestaudio/best")
      (message "Starting streaming..."))

And bind it to a key in ytel-mode with

(define-key ytel-mode-map "y" #'ytel-watch)

This is of course just an example. You can similarly implement functions to:

  • open a video in the browser,
  • download a video,
  • download just the audio of a video,

by relying on the correct external tool.

It is also possible to customize the sorting criterion of the results by setting the variable ytel-sort-criterion to one of the following symbols relevance, rating, upload_date or view_count. The default value is relevance.

Potential problems and potential fixes

ytel does not use the official YouTube APIs but relies on the Invidious APIs (that in turn circumvent YouTube ones). The variable ytel-invidious-api-url points to the invidious instance (by default https://invidio.us) to use; you might not need to ever touch this, but if invidio.us goes down keep in mind that you can choose another instance. Moreover the default Invidious instance is generally speaking stable, but sometimes your ytel-search might hang; in that case C-g and retry.

Currently some wide unicode characters (such as Chinese/Japanese/Korean characters) are very likely to mess up the *ytel* buffer. The messing up is not that bad but things will not be perfectly aligned. Fixing this problem will most likely require a rewrite of how the ytel buffer is actually drawn. We're (somewhat) working on it.

Extra

There's an extension to browse comments and video information.

Contributing

Feel free to open an issue or send a pull request. I'm quite new to writing Emacs packages so any help is appreciated.

FAQ

Why?

One can easily subscribe to YouTube channels via an RSS feed and access it in Emacs via elfeed but sometimes I want to search YouTube for videos of people I don't necessarily follow (e.g. for searching a tutorial, or music, or wasting some good time) and being able to do that without switching to a browser is nice.

What about helm-youtube and ivy-youtube?

First of all those packages require you to get a Google API key, while ytel uses the Invidious APIs that in turn do not use the official Google APIs.

Moreover those packages are designed to select a YouTube search result and play it directly in your browser while ytel is really a way to collect search results in an elfeed-like buffer and make them accessible to the user via functions such as ytel-get-current-video so the user gets to decide what to to with them.

ytel's People

Contributors

juergenhoetzel avatar manabiseijin avatar pablobc-mx avatar seblemaguer avatar syohex avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

ytel's Issues

hard time getting ytel to work with new invidious api url

https://invidio.us is down. I tried switching to another one of the mirrors e.g. (setq ytel-invidious-api-url "https://invidious.snopyta.org/") but to no avail. I either get a "wrong-type argument (array timed out)" or an empty search buffer or "end of file while parsing json". Do you experience the same thing or am I the only one?

ytel-show

Hi, I have made a plugin package for ytel.

support for "date" limit

I added in my branch support for date limitation, sorry did see that I did not have commited it and not in the mental state to do that now, so I post the relevant code here for now:

(defun ytel--query (string n)
...
`(("q" ,string)
("date" ,(symbol-name ytel-date-criterion))
("sort_by" ,(symbol-name ytel-sort-criterion))
("page" n)
("fields" ,ytel-invidious-default-query-fields))

(defcustom ytel-date-criterion 'year
  "Criterion to date limit the results of the search query."
  :type 'symbol
  :options '(hour day week month year)
  :group 'ytel)

(defun ytel-search (query)
  "Search youtube for `QUERY', and redraw the buffer."
  (interactive "sSearch terms: ")
  (setf ytel-current-page 1)
  (let* ((query-words (split-string query))
	 (terms (seq-group-by (lambda (elem)
				(s-contains-p ":" elem))
			      query-words)))
    (setf ytel-search-term
	  (s-join " " (assoc-default nil terms)))
    (if-let ((date (seq-find
		    (lambda (s) (s-starts-with-p "date:" s) )
		    (assoc-default t terms))))
	(setf ytel-date-criterion (intern (substring date 5)))
      (setf ytel-date-criterion 'year)))
  (setf ytel-videos (ytel--query ytel-search-term ytel-current-page))
  (ytel--draw-buffer))

It may not be the best way to use the search term to limit you could also implement it as toggle, where you can toggle through day/week/month/year.

Search term fails with Args out of Range

If I search "React Nightwish" it fails:

seq-subseq: Args out of range: "REACTING to NIGHTWISH (Ghost River) ๐Ÿ‘ป๐Ÿž๐Ÿ”ฅ", 0, 40

It probably has something to do with this symbols at the end of the title not sure if that is unicode or what, and why it exactly fails.

Ok found the problem, the function string-width counts the length as 41, if I replace it with length it detects 39.

For some reason it counts the ghost and the fire symbol as 2 length the symbol in the middle it counts as 1, but whatever the reason is that string-width don't counts correctly length does, something about proportional fonts I guess, but something is going wrong.

I set ytel-title-video-reserved-space to 40, otherwise you probably don't get the error.

Search for channels?

It'd be nice if this tool could be use to find and "subscribe" to channels by retrieving their channel ID and returning an RSS feed URL, ready to be pasted into - for example - org-elfeed.

play/queue multiple marked videos

if you use umpv as starter for mpv it does queue new videos in a playlist.

The problem is that you have to press 10 times enter as example to queue 10 videos you can't mark as example all videos in the result buffer and queue them with 1 shortcut.

I tried to add it then I realized that you don't use the tabulated-list:
https://www.gnu.org/software/emacs/manual/html_node/elisp/Tabulated-List-Mode.html

Which would have made that easy to implement (copy and paste + small changes from my kodi-remote mode), would it make sense to use tabulated-list or do you think implement such marked mode would be easy doable without. I of course could fork it and rewrite it with tabulated-list-mode. I think having only 1 buffer for search results is ideal, so a buffer for search history where you can open with enter search results would probably good but then I would argue or question if there tabulated lists would not helpful, too.

Did you not know about tabulated-list-mode or do you have other reasons to not use it?

Use display-buffer instead of switch-to-buffer

Thank you for ytel, this is an excellent piece of piping. Together with RSS feeds of youtube channels I'm subscribed to, I rarely need to visit youtube any more.

This is about the window creation method for ytel:

(defun ytel ()
  "Enter ytel."
  (interactive)
  (switch-to-buffer (ytel-buffer))
  (unless (eq major-mode 'ytel-mode)
    (ytel-mode))
  (when (seq-empty-p ytel-search-term)
    (call-interactively #'ytel-search)))

Consider using display-buffer or pop-to-buffer instead of switch-to-buffer here? The former two are configurable by the user through display-buffer-alist or using a package like shackle.el, so that they can, for instance, have ytel launch in a side window or a new frame always. Or indeed, choose the window used for displaying ytel based on an arbitrary predicate and from the full complement of window types emacs supports. switch-to-buffer pre-dates the display-buffer functionality and is completely inflexible.

Fork or merge

I mentioned before that using tabulated-list can be a good way to as example mitigate the font-issue but also to have some good like sorting by column and so on, also I could delete some code by not loosing functionality.

So I have I don't know if rewritten is the correct word migrated is probably better your code to a tabulated-list variant in the branch. Yet I noticed a few things I forgot that makes that basically not a 1:1 replacement with some positive and some negative effects.

  1. column names are basically hardcoded and replace the title lane, so it changes the looks, the information you have in that line I had to put into the mode line.
  2. especially because I had put the search title in the buffer-name I got nearly by mistake the functionality that each search outside of this buffer creates a new buffer for this search. So you can have multiple searches open at the same time and refresh them. Which can be very useful but also be confusing I guess.

Now we share still 80-90% of the same code, but it behaves and looks pretty differently, so I would assume that you will not merge this tabulated-list code change?
Here you can see a picture of it with my theme:
https://github.com/spiderbit/ytel/tree/tabulated-list

If that is the case it would probably be best to find a different name for my code and make a clean cut fork? The disadvantage is that we then have to at least rename all name space references in functions and variables if we exchange commits/patches.

I should have most things implemented i want for now, I want a sort sub-buffer like the one in magit that pops up below so that you can as example press r d for sort by date and r n for sort by name... rotating through the possible sort options by repetitively press r is not ideal, but otherwise I have no current plans on further improvements.

Cannot find any results

M-x ytel
search: Emacs
ytel search gives me:
json-read: End of file while parsing JSON
:(

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.