Skip to content

Commit eb484d4

Browse files
committed
Add paw-say-word-oxford
1 parent e594c0e commit eb484d4

File tree

2 files changed

+148
-75
lines changed

2 files changed

+148
-75
lines changed

paw-anki.el

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
:type 'boolean
1818
:group 'paw-anki)
1919

20-
(defvar paw-anki-download-word-english-functions '(paw-say-word-cambridge paw-youdao-say-word))
20+
(defvar paw-anki-download-word-english-functions '(paw-say-word-cambridge paw-say-word-oxford paw-youdao-say-word))
2121
(defvar paw-anki-download-word-japanese-functions '(paw-say-word-jpod101-alternate))
2222

23-
(defcustom paw-anki-download-sound-functions '(paw-say-word-cambridge paw-say-word-jpod101-alternate paw-edge-tts-say-word paw-youdao-say-word)
23+
(defcustom paw-anki-download-sound-functions '(paw-say-word-cambridge paw-say-word-oxford paw-say-word-jpod101-alternate paw-edge-tts-say-word paw-youdao-say-word)
2424
"The functions to download sound file when pushing note to Anki, one by one. If any one success, it will break."
2525
:type 'list
2626
:group 'paw-anki)

paw-util.el

Lines changed: 146 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -420,10 +420,10 @@ If LAMBDA is non-nil, call it after creating the download process."
420420
:type 'string)
421421

422422

423-
(defvar paw-say-word-english-functions '(paw-say-word-cambridge paw-youdao-say-word))
423+
(defvar paw-say-word-english-functions '(paw-say-word-cambridge paw-say-word-oxford paw-youdao-say-word))
424424
(defvar paw-say-word-japanese-functions '(paw-say-word-jpod101-alternate))
425425

426-
(defcustom paw-say-word-functions '(paw-say-word-cambridge paw-say-word-jpod101-alternate paw-edge-tts-say-word paw-youdao-say-word paw-say-word-forvo)
426+
(defcustom paw-say-word-functions '(paw-say-word-cambridge paw-say-word-oxford paw-say-word-jpod101-alternate paw-edge-tts-say-word paw-youdao-say-word paw-say-word-forvo)
427427
"The functions to download and play sound file one by one, used in `paw-say-word' if arg is nil. If any one success, it will break."
428428
:type 'list
429429
:group 'paw)
@@ -474,71 +474,39 @@ will prompt you every first time when download the audio file. "
474474
(source (plist-get args :source))
475475
(word-hash (md5 word))
476476
(mp3-file (concat (expand-file-name word-hash paw-tts-cache-dir) ".mp3"))
477-
(mp3-file-edge-tts (concat (expand-file-name (concat word-hash "+edge-tts") paw-tts-cache-dir) ".mp3"))
478-
(mp3-file-youdao (concat (expand-file-name (concat word-hash "+youdao") paw-tts-cache-dir) ".mp3"))
479-
(mp3-file-jisho (concat (expand-file-name (concat word-hash "+jisho") paw-tts-cache-dir) ".mp3"))
480-
(mp3-file-jpod101 (concat (expand-file-name (concat word-hash "+jpod101") paw-tts-cache-dir) ".mp3"))
481-
(mp3-file-jpod101-alternate (concat (expand-file-name (concat word-hash "+jpod101-alternate") paw-tts-cache-dir) ".mp3"))
482-
(subtitle-file (concat (expand-file-name word-hash paw-tts-cache-dir) ".vtt"))
483-
(audio-url))
477+
(audio-url)
478+
(lambda (lambda (file)
479+
(if (and (file-exists-p file) (> (file-attribute-size (file-attributes file)) 0) )
480+
(copy-file file mp3-file t)))))
484481
(make-directory paw-tts-cache-dir t) ;; ensure cache directory exists
485482
(if refresh
486483
(message "Re-Downloading the audio file..."))
487-
(when (or (and refresh (file-exists-p mp3-file))
488-
(and (file-exists-p mp3-file) (= (file-attribute-size (file-attributes mp3-file)) 0) ))
489-
(delete-file mp3-file))
490-
(when (or (and refresh (file-exists-p subtitle-file))
491-
(and (file-exists-p subtitle-file) (= (file-attribute-size (file-attributes subtitle-file)) 0) ))
492-
(delete-file subtitle-file))
493-
(when (or (and refresh (file-exists-p mp3-file-edge-tts))
494-
(and (file-exists-p mp3-file-edge-tts) (= (file-attribute-size (file-attributes mp3-file-edge-tts)) 0) ))
495-
(delete-file mp3-file-edge-tts))
496-
(when (or (and refresh (file-exists-p mp3-file-jisho))
497-
(and (file-exists-p mp3-file-jisho) (= (file-attribute-size (file-attributes mp3-file-jisho)) 0) ))
498-
(delete-file mp3-file-jisho))
499-
(when (or (and refresh (file-exists-p mp3-file-youdao))
500-
(and (file-exists-p mp3-file-youdao) (= (file-attribute-size (file-attributes mp3-file-youdao)) 0) ))
501-
(delete-file mp3-file-youdao))
502-
(when (or (and refresh (file-exists-p mp3-file-jpod101))
503-
(and (file-exists-p mp3-file-jpod101) (= (file-attribute-size (file-attributes mp3-file-jpod101)) 0) ))
504-
(delete-file mp3-file-jpod101))
505-
(when (or (and refresh (file-exists-p mp3-file-jpod101-alternate))
506-
(and (file-exists-p mp3-file-jpod101-alternate) (= (file-attribute-size (file-attributes mp3-file-jpod101-alternate)) 0) ))
507-
(delete-file mp3-file-jpod101-alternate))
508-
(let ((source (if source (completing-read (format "Select Audio Playback Source (%s): " word) '("edge-tts" "forvo" "youdao" "cambridge" "jisho" "jpod101" "jpod101-alternate") nil t) "default")))
484+
(paw-say-word-delete-mp3-file (concat word-hash "+edge-tts") refresh)
485+
(paw-say-word-delete-mp3-file (concat word-hash "+youdao") refresh)
486+
(paw-say-word-delete-mp3-file (concat word-hash "+jisho") refresh)
487+
(paw-say-word-delete-mp3-file (concat word-hash "+jpod101") refresh)
488+
(paw-say-word-delete-mp3-file (concat word-hash "+jpod101-alternate") refresh)
489+
(paw-say-word-delete-mp3-file (concat word-hash "+frovo") refresh)
490+
(paw-say-word-delete-mp3-file (concat word-hash "+cambridge") refresh)
491+
(paw-say-word-delete-mp3-file (concat word-hash "+oxford") refresh)
492+
(let ((source (if source (completing-read (format "Select Audio Playback Source (%s): " word) '("edge-tts" "forvo" "youdao" "cambridge" "oxford" "jisho" "jpod101" "jpod101-alternate") nil t) "default")))
509493
(pcase source
510494
("default"
511495
(if (file-exists-p mp3-file)
512496
(setq audio-url mp3-file)
513497
(setq audio-url mp3-file)
514-
(paw-say-word-function paw-say-word-functions word
515-
(lambda (file)
516-
(if (and (file-exists-p file) (> (file-attribute-size (file-attributes file)) 0) )
517-
(copy-file file mp3-file t))))))
518-
498+
(paw-say-word-function paw-say-word-functions word lambda)))
519499
("edge-tts"
520500
(paw-edge-tts-say-word word
521501
:lang (completing-read (format "Select TTS Sound Engine (%s): " word) '("en" "ja" "zh" "zh-Hant" "ko" "Multilingual") nil t)
522-
:lambda (lambda (file)
523-
(if (and (file-exists-p file) (> (file-attribute-size (file-attributes file)) 0) )
524-
(copy-file file mp3-file t)))))
502+
:lambda lambda))
525503
("forvo"
526504
(paw-say-word-forvo word
527505
:lang (completing-read (format "Select TTS Sound Engine (%s): " word) '("en" "ja" "zh" "ko") nil t)
528-
:lambda (lambda (file)
529-
(if (and (file-exists-p file) (> (file-attribute-size (file-attributes file)) 0) )
530-
(copy-file file mp3-file t)))))
531-
532-
("youdao"
533-
(paw-youdao-say-word word :lambda (lambda (file)
534-
(if (and (file-exists-p file) (> (file-attribute-size (file-attributes file)) 0) )
535-
(copy-file file mp3-file t)))))
536-
537-
("cambridge"
538-
(paw-say-word-cambridge word :lambda (lambda (file)
539-
(if (and (file-exists-p file) (> (file-attribute-size (file-attributes file)) 0) )
540-
(copy-file file mp3-file t)))))
541-
506+
:lambda lambda))
507+
("youdao" (paw-youdao-say-word word :lambda lambda))
508+
("cambridge" (paw-say-word-cambridge word :lambda lambda))
509+
("oxford" (paw-say-word-oxford word :lambda lambda))
542510
("jisho"
543511
(paw-say-word-jisho word
544512
;; have to provide a reading
@@ -549,10 +517,7 @@ will prompt you every first time when download the audio file. "
549517
(if (string= input paw-play-source-button)
550518
word
551519
input)))
552-
:lambda (lambda (file)
553-
(if (and (file-exists-p file) (> (file-attribute-size (file-attributes file)) 0) )
554-
(copy-file file mp3-file t)))))
555-
520+
:lambda lambda))
556521
("jpod101"
557522
(paw-say-word-jpod101 word
558523
;; have to provide a reading
@@ -563,20 +528,18 @@ will prompt you every first time when download the audio file. "
563528
(if (string= input paw-play-source-button)
564529
word
565530
input)))
566-
:lambda (lambda (file)
567-
(if (and (file-exists-p file) (> (file-attribute-size (file-attributes file)) 0) )
568-
(copy-file file mp3-file t)))))
569-
570-
("jpod101-alternate"
571-
(paw-say-word-jpod101-alternate word
572-
:lambda (lambda (file)
573-
(if (and (file-exists-p file) (> (file-attribute-size (file-attributes file)) 0) )
574-
(copy-file file mp3-file t)))))))
575-
531+
:lambda lambda))
532+
("jpod101-alternate" (paw-say-word-jpod101-alternate word :lambda lambda))))
576533
(if (and audio-url (file-exists-p audio-url) )
577534
(setq paw-say-word-running-process (start-process "*paw say word*" nil "mpv" audio-url)))
578535
(if (and audio-url (file-exists-p audio-url) ) audio-url )))
579536

537+
(defun paw-say-word-delete-mp3-file (hash refresh)
538+
(let* ((mp3-file (concat (expand-file-name hash paw-tts-cache-dir) ".mp3")))
539+
(when (or (and refresh (file-exists-p mp3-file))
540+
(and (file-exists-p mp3-file) (= (file-attribute-size (file-attributes mp3-file)) 0) ))
541+
(delete-file mp3-file))))
542+
580543
(defun paw-play-mp3-process-sentiel(process event mp3-file)
581544
;; When process "finished", then begin playback
582545
(when (string= event "finished\n")
@@ -1148,7 +1111,11 @@ if `paw-detect-language-p' is t, or return as `paw-non-ascii-language' if
11481111
(funcall select-func items)) )
11491112
(if lambda (funcall lambda nil) ))
11501113

1151-
)))) )))
1114+
)))
1115+
:error
1116+
(cl-function (lambda (&rest args &key error-thrown &allow-other-keys)
1117+
(if lambda (funcall lambda nil) )
1118+
(message "Failed to find audio URL, %s" error-thrown)))) )))
11521119

11531120
;; (paw-say-word-jpod101-alternate "日本" "") ;; all sounds
11541121
;; (paw-say-word-jpod101-alternate "日本" "日本") ;; all sounds
@@ -1242,7 +1209,106 @@ if `paw-detect-language-p' is t, or return as `paw-non-ascii-language' if
12421209
("us" (funcall select-func (list us-voice-url)))
12431210
("uk" (funcall select-func (list uk-voice-url)))
12441211
(_ (funcall select-func items))) )
1245-
(if lambda (funcall lambda nil) )))))) )))
1212+
(if lambda (funcall lambda nil) )))))
1213+
:error
1214+
(cl-function (lambda (&rest args &key error-thrown &allow-other-keys)
1215+
(if lambda (funcall lambda nil) )
1216+
(message "Failed to find audio URL, %s" error-thrown)))) )))
1217+
1218+
1219+
(defvar pay-say-word-oxford-audio-list nil)
1220+
1221+
1222+
(defcustom paw-say-word-oxford-voice "us"
1223+
"The voice of the oxford dictionary, either us or uk."
1224+
:group 'paw
1225+
:type 'string)
1226+
1227+
(defun paw-say-word-oxford (term &rest args)
1228+
(let* ((reading (or (plist-get args :reading) ""))
1229+
(lambda (plist-get args :lambda))
1230+
(download-only (plist-get args :download-only))
1231+
(select-func (lambda (items)
1232+
(if-let* ((choice (if (> (length items) 1)
1233+
(completing-read "Select sound: " items)
1234+
(caar items)))
1235+
(audio-url (car (assoc-default choice items) )))
1236+
(paw-download-and-say-word
1237+
:source-name "oxford"
1238+
:word term
1239+
:audio-url audio-url
1240+
:lambda lambda
1241+
:download-only download-only)
1242+
(message "No valid audio url")))))
1243+
(if (and (stringp (caar pay-say-word-oxford-audio-list ))
1244+
(string-match-p term (caar pay-say-word-oxford-audio-list )) )
1245+
1246+
(pcase paw-say-word-oxford-voice
1247+
("us" (funcall select-func (list (cl-find-if (lambda (item)
1248+
(string-match-p "\\[us\\]" (car item)))
1249+
pay-say-word-oxford-audio-list))))
1250+
("uk" (funcall select-func (list (cl-find-if (lambda (item)
1251+
(string-match-p "\\[uk\\]" (car item)))
1252+
pay-say-word-oxford-audio-list))))
1253+
(_ (funcall select-func pay-say-word-oxford-audio-list)))
1254+
1255+
(request (format "https://www.oxfordlearnersdictionaries.com/definition/english/%s" (downcase term))
1256+
:parser 'buffer-string
1257+
:headers '(("User-Agent" . "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36")
1258+
("Content-Type" . "application/x-www-form-urlencoded"))
1259+
:success (cl-function
1260+
(lambda (&key data &allow-other-keys)
1261+
;; Parse HTML
1262+
1263+
;; (with-temp-file "~/test.html"
1264+
;; (insert data))
1265+
(let* ((parsed-html (with-temp-buffer
1266+
(insert data)
1267+
(libxml-parse-html-region (point-min) (point-max))))
1268+
;; Get all 'dc-result-row' elements
1269+
(uk-voice (dom-by-class parsed-html "phons_br"))
1270+
(us-voice (dom-by-class parsed-html "phons_n_am"))
1271+
(items)
1272+
(us-voice-url)
1273+
(uk-voice-url))
1274+
1275+
;; (with-temp-file "~/test.html"
1276+
;; (insert data))
1277+
(when-let* ((audio-elem (dom-by-class us-voice "pron-us"))
1278+
(audio-url (dom-attr audio-elem 'data-src-mp3)))
1279+
(setq us-voice-url (list (format "%s [us]" (propertize term 'face 'paw-file-face)) audio-url))
1280+
(push us-voice-url items))
1281+
1282+
;; (pp us-voice-url)
1283+
1284+
(when-let* ((audio-elem (dom-by-class uk-voice "pron-uk"))
1285+
(audio-url (dom-attr audio-elem 'data-src-mp3)))
1286+
(setq uk-voice-url (list (format "%s [uk]" (propertize term 'face 'paw-file-face)) audio-url))
1287+
(push uk-voice-url items))
1288+
1289+
;; (pp uk-voice-url)
1290+
(if items
1291+
(progn
1292+
(setq pay-say-word-oxford-audio-list items)
1293+
(pcase paw-say-word-oxford-voice
1294+
("us" (funcall select-func (list us-voice-url)))
1295+
("uk" (funcall select-func (list uk-voice-url)))
1296+
(_ (funcall select-func items))) )
1297+
(if lambda (funcall lambda nil) ))
1298+
)
1299+
1300+
1301+
))
1302+
1303+
:error
1304+
(cl-function (lambda (&rest args &key error-thrown &allow-other-keys)
1305+
(if lambda (funcall lambda nil) )
1306+
(message "Failed to find audio URL, %s" error-thrown)))
1307+
) )))
1308+
1309+
1310+
;; (paw-say-word-oxford "hello")
1311+
;; (paw-say-word-oxford "world")
12461312

12471313

12481314

@@ -1296,10 +1362,17 @@ if `paw-detect-language-p' is t, or return as `paw-non-ascii-language' if
12961362
(info (string-trim (dom-texts (dom-by-class res "ofLink")) )))
12971363
;; (message "%s %s %s" term username audio-url)
12981364
(push (list (format "%s Pronunciation by %s %s" (propertize term 'face 'paw-file-face) info username) audio-url) list-play)))
1299-
(when list-play
1300-
(setq list-play (nreverse list-play))
1301-
(setq paw-say-word-forvo-audio-list list-play)
1302-
(funcall select-func list-play)))))))))
1365+
(if list-play
1366+
(progn
1367+
(setq list-play (nreverse list-play))
1368+
(setq paw-say-word-forvo-audio-list list-play)
1369+
(funcall select-func list-play) )
1370+
(if lambda (funcall lambda nil) )))))
1371+
:error
1372+
(cl-function (lambda (&rest args &key error-thrown &allow-other-keys)
1373+
(if lambda (funcall lambda nil) )
1374+
(message "Failed to find audio URL, %s" error-thrown)))
1375+
))))
13031376

13041377
;; (paw-say-word-forvo "hello")
13051378

0 commit comments

Comments
 (0)