Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image support #65

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions smudge-api.el
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,18 @@ Call CALLBACK with the parsed JSON response."
"Return the owner id of the given playlist JSON object."
(smudge-api-get-item-id (gethash 'owner json)))

(defun smudge-api-get-song-art-url (song)
"Return the medium sized image url for a SONG."
(let* ((album (gethash 'album song))
(image (and album (nth 2 (gethash 'images album)))))
(and image (gethash 'url image))))

(defun smudge-api-get-playlist-art-url (playlist)
"Return the smallest possible image url for PLAYLIST (we only need 64x64 and it gets scaled)."
(let* ((images (gethash 'images playlist))
(image (and images (or (nth 3 images) (nth 2 images) (first images)))))
(and image (gethash 'url image))))

(defun smudge-api-search (type query page callback)
"Search artists, albums, tracks or playlists.
Call CALLBACK with PAGE of items that match QUERY, depending on TYPE."
Expand Down Expand Up @@ -463,6 +475,15 @@ Call CALLBACK with results."
nil
callback)))

(defun smudge-api-album (album-id callback)
"Call CALLBACK with info for album with ALBUM-ID."
(smudge-api-call-async
"GET"
(format "/albums/%s"
(url-hexify-string album-id))
nil
callback))

(defun smudge-api-album-tracks (album page callback)
"Call CALLBACK with PAGE of tracks for ALBUM."
(let ((album-id (smudge-api-get-item-id album))
Expand Down
78 changes: 78 additions & 0 deletions smudge-image.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
;;; smudge-image.el --- Smudge image support library -*- lexical-binding: t; -*-

;; Copyright (C) 2021 Jason Dufair

;;; Commentary:

;; This library implements methods that support image display for smudge

;;; Code:

(defcustom smudge-show-artwork t
"Whether to show artwork when searching for tracks."
:type 'boolean
:group 'smudge)

(defvar smudge-artwork-fetch-target-count 0)
(defvar smudge-artwork-fetch-count 0)

(defun smudge-image-increment-count ()
"Increment count of fetched (or the absence of) images. Handle redisplay."
(setq smudge-artwork-fetch-count (1+ smudge-artwork-fetch-count))
(when (= smudge-artwork-fetch-count smudge-artwork-fetch-target-count)
(setq inhibit-redisplay nil)))

(defun smudge-image-tabulated-list-print-entry (id cols)
"Insert a Tabulated List entry at point.
This implementation asynchronously inserts album images in the
table buffer after the rows are printed. It reimplements most of
the `tabulated-list-print-entry' function but depends on a url
being the first column's data. It does not print that url in the
column. ID is a Lisp object identifying the entry to print, and
COLS is a vector of column descriptors."
(let ((beg (point))
(x (max tabulated-list-padding 0))
(ncols (length tabulated-list-format))
(inhibit-read-only t)
(cb (current-buffer))
(image-url (aref cols 0)))
(if (> tabulated-list-padding 0)
(insert (make-string x ?\s)))
(if image-url
(url-retrieve image-url
(lambda (_)
(let ((img (create-image
(progn
(goto-char (point-min))
(re-search-forward "^$")
(forward-char)
(delete-region (point) (point-min))
(buffer-substring-no-properties (point-min) (point-max)))
nil t :width 64)))
;; kill the image data buffer. We have the data now
(kill-buffer)
;; switch to the table buffer
(set-buffer cb)
(let ((inhibit-read-only t))
(save-excursion
(goto-char beg)
(put-image img (point) "track image" 'left-margin)))
(smudge-image-increment-count))))
(smudge-image-increment-count))
(insert ?\s)
(let ((tabulated-list--near-rows ; Bind it if not bound yet (Bug#25506).
(or (bound-and-true-p tabulated-list--near-rows)
(list (or (tabulated-list-get-entry (point-at-bol 0))
cols)
cols))))
;; don't print the URL column
(dotimes (n (- ncols 1))
(setq x (tabulated-list-print-col (+ n 1) (aref cols (+ n 1)) x))))
(insert ?\n)
;; Ever so slightly faster than calling `put-text-property' twice.
(add-text-properties
beg (point)
`(tabulated-list-id ,id tabulated-list-entry ,cols))))

(provide 'smudge-image)
;;; smudge-image.el ends here
56 changes: 39 additions & 17 deletions smudge-playlist.el
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@
(require 'smudge-api)
(require 'smudge-controller)
(require 'smudge-track)
(require 'smudge-image)

(defvar smudge-user-id)
(defvar smudge-current-page)
(defvar smudge-browse-message)
(defvar smudge-selected-playlist)
(defvar smudge-query)
(defvar smudge-artwork-fetch-target-count 0)
(defvar smudge-artwork-fetch-count 0)

(defvar smudge-playlist-search-mode-map
(let ((map (make-sparse-keymap)))
Expand Down Expand Up @@ -141,11 +144,13 @@
(defun smudge-playlist-set-list-format ()
"Configures the column data for the typical playlist view."
(setq tabulated-list-format
(vector `("Playlist Name" ,(- (window-width) 45) t)
'("Owner Id" 30 t)
'("# Tracks" 8 (lambda (row-1 row-2)
(< (smudge-api-get-playlist-track-count (car row-1))
(smudge-api-get-playlist-track-count (car row-2)))) :right-align t))))
(vector
`("" -1) ;; image url column - do not display
`("Playlist Name" ,(- (window-width) 45) t)
'("Owner Id" 30 t)
'("# Tracks" 8 (lambda (row-1 row-2)
(< (smudge-api-get-playlist-track-count (car row-1))
(smudge-api-get-playlist-track-count (car row-2)))) :right-align t))))

(defun smudge-playlist-search-print (playlists page)
"Append PLAYLISTS to PAGE of the current playlist view."
Expand All @@ -154,18 +159,35 @@
(let ((user-id (smudge-api-get-playlist-owner-id playlist))
(playlist-name (smudge-api-get-item-name playlist)))
(push (list playlist
(vector (cons playlist-name
(list 'face 'link
'follow-link t
'action `(lambda (_) (smudge-playlist-tracks))
'help-echo (format "Show %s's tracks" playlist-name)))
(cons user-id
(list 'face 'link
'follow-link t
'action `(lambda (_) (smudge-user-playlists ,user-id))
'help-echo (format "Show %s's public playlists" user-id)))
(number-to-string (smudge-api-get-playlist-track-count playlist))))
entries)))
(vector
(if smudge-show-artwork (smudge-api-get-playlist-art-url playlist) "")
(cons playlist-name
(list 'face 'link
'follow-link t
'action `(lambda (_) (smudge-playlist-tracks))
'help-echo (format "Show %s's tracks" playlist-name)))
(cons user-id
(list 'face 'link
'follow-link t
'action `(lambda (_) (smudge-user-playlists ,user-id))
'help-echo (format "Show %s's public playlists" user-id)))
(number-to-string (smudge-api-get-playlist-track-count playlist))))
entries)))
(setq tabulated-list-printer #'tabulated-list-print-entry)
(when smudge-show-artwork
(setq tabulated-list-printer #'smudge-image-tabulated-list-print-entry)
(setq smudge-artwork-fetch-target-count
(+ (length playlists) (if (eq 1 page) 0 (count-lines (point-min) (point-max)))))
(setq smudge-artwork-fetch-count 0)
(setq line-spacing 10)
(message "Fetching playlists...")
;; in case the fetch chokes somehow, don't lock up all of emacs forever
(run-at-time "3 sec" nil (lambda () (setq inhibit-redisplay nil)))
;; Undocumented function. Could be dangerous if there's a bug
(setq inhibit-redisplay t)
(message "inhibit-redisplay: %s" inhibit-redisplay)
(setq left-margin-width 6)
(set-window-buffer (selected-window) (current-buffer)))
(when (eq 1 page) (setq-local tabulated-list-entries nil))
(smudge-playlist-set-list-format)
(setq-local tabulated-list-entries (append tabulated-list-entries (nreverse entries)))
Expand Down
Loading