I'm writing code to generate the rss feed of my selfhost podcast and I need a function that would return a type depending on the file extension of podcast item.
For example, if the podcast file (item) has the extension mp4
, I need to return the string video/mp4
. This is needed to generate the tag <enclosure>
as described in A Podcaster’s Guide to RSS.
This problem could be solved through a function to condition enumeration. For example,
(defun podcast-return-type (ext)
"return type string for item file extension"
(cond
((string= ext "m4a") (identity "audio/x-m4a"))
((string= ext "mp4") (identity "video/mp4"))
((string= ext "mp3") (identity "audio/mpeg"))
((string= ext "mov") (identity "video/quicktime"))
((string= ext "m4v") (identity "video/x-m4v"))
((string= ext "pdf") (identity "application/pdf"))
(t (identity "not applyed"))))
But I wanted to solve it through a property list. I ran into a problem: I can't get the value if the key is stored in a variable.
(setq podcast-list '(mp4 "video/mp4" mp3 "audio/mpeg" pdf "application/pdf")) ;; key value
(setq ext (file-name-extension "~/podcast/podcast-item.mp4")) ---> "mp4"
(plist-get podcast-list ext) ----> nil
(plist-get podcast-list 'mp4) ----> "video/x-m4v"
How can I get the value of a plist if the key is in a variable? Or is there a more elegant way to solve this problem? I feel like the solution is somewhere on the surface, but I'm stuck.
That's because your keys are symbols
and the value of ext
is a string
. Those are completely different types, so they never match.
You can convert your string to a symbol by intern
ing it:
(plist-get podcast-list (intern ext))
"video/mp4"
You can also convert the keys to string
, but then you need to specify a different comparison function in plist-get
- it uses eq
by default which will not work for strings:
(setq podcast-list '("mp4" "video/mp4" "mp3" "audio/mpeg" "pdf" "application/pdf"))
(setq ext (file-name-extension "~/podcast/podcast-item.mp4"))
(plist-get podcast-list ext #'string=)
"video/mp4"
eq
is much cheaper than string=
, so most people would probably prefer the first version.
EDIT: I was intrigued by the performance figures the OP posted in a comment, so I tried to reproduce them with this file:
(defun podcast-return-type (ext)
"return type string for item file extension"
(cond
((string= ext "m4a") (identity "audio/x-m4a"))
((string= ext "mp4") (identity "video/mp4"))
((string= ext "mp3") (identity "audio/mpeg"))
((string= ext "mov") (identity "video/quicktime"))
((string= ext "m4v") (identity "video/x-m4v"))
((string= ext "pdf") (identity "application/pdf"))
(t (identity "not applied"))))
(setq podcast-list '(m4a "audio/x-m4a" mp4 "video/mp4" mp3 "audio/mpeg" mov "/video/quicktime" m4v "video/x-m4v" pdf "application/pdf"))
(print (benchmark-run 100000 (podcast-return-type "mp4")))
(print (benchmark-run 100000 (plist-get podcast-list (intern "mp4"))))
(print (benchmark-run 100000 (podcast-return-type "pdf")))
(print (benchmark-run 100000 (plist-get podcast-list (intern "pdf"))))
Running it with emacs --batch --load test.el
I got the following
results:
(0.026426384 0 0.0) ;; function mp4
(0.015171091000000001 0 0.0) ;; plist-get mp4
(0.043410812 0 0.0) ;; function pdf
(0.016731469 0 0.0) ;; plist-get pdf
I tried two keys: one near the beginning of the list and one near the end. The function shows a substantial slowdown between the two cases (almost a factor of 2), while the plist-get
is about 7% slower in the second case.
But in neither case, did the function beat plist-get
: the function is slower by a factor of 1.5 in the first case and by 2.5 in the second case. Note I did 100000 repetitions of each.
BTW, you can speed up your function a bit by getting rid of the unnecessary identity
function calls:
(defun podcast-return-type (ext)
"return type string for item file extension"
(cond
((string= ext "m4a") "audio/x-m4a")
((string= ext "mp4") "video/mp4")
((string= ext "mp3") "audio/mpeg")
((string= ext "mov") "video/quicktime")
((string= ext "m4v") "video/x-m4v")
((string= ext "pdf") "application/pdf")
(t "not applied")))
but even so, the plist-get
implementation is still faster:
(0.022579204000000002 0 0.0) ; function mp4
(0.012907366 0 0.0) ; plist-get mp4
(0.038039411 0 0.0) ; function pdf
(0.014557089 0 0.0) ; plist-get pdf