Let's write β

プログラミング中にできたことか、思ったこととか

ネットがない環境に行くという事

昨今はネットに接続できる環境に居る事が多く、ここ3日ほどネットの接続環境が無い環境にいっており、
自分の頭とPC内の資料以外にたよれない環境にいました。そんな環境にいながらもがいていると、どれほど普段自分がネットや別のマシン等の外部リソースに助けられているのかという事を実感しました。
それとともに、「ネットがなくても何か仕事を無しとげられる環境をつねに構築していなければ」と思い直す良い機会になりました。
ネットが無く、しかも音楽プレーヤーを途中で一時紛失してしまうという事になり仕事の合間に聞きたい音楽を快適に聞くのが面倒になりました。GUIで音楽プレーヤーを起動しても良いのですが、リソースを食うので嫌です。そこで(?)とりあえず、音楽の再生ができるようにちょっとしてみようとおもいLispでプログラムを書きました(なんだろ、すごく矛盾しているような気がする)

(ql:quickload :cl-fad)

(defpackage :lvlc
  (:use :cl
        :cl-fad)
  (:export
    :<player>
    :load-playlist
    :show-playlist
    :stop-play
    :play-file
    :play-playlist
    :play))

(in-package :lvlc)

(defun show-all-music-files ()
  (list-directory #p"~/Music"))

(defclass <player> ()
  ((playlist :initform nil :initarg :playlist :accessor playlist)
   (play-proc :initform nil :accessor play-proc)
   (now-playing :initform nil :reader now-playing)))

(defmethod load-playlist (filepath-list (player <player>))
  (setf (playlist player) filepath-list))

(defmethod show-playlist ((player <player>))
  (loop for idx from 0 upto (1- (length (playlist player)))
        do
        (format t "~A: ~A~%" idx (nth idx (playlist player)))))

(defmethod playing-p ((player <player>))
  (and (not (null (play-proc player)))
       (sb-ext:process-alive-p (play-proc player))))

(defmethod stop-play ((player <player>))
  (when (playing-p player)
    (sb-ext:process-kill (play-proc player) 9)))

(defmethod play-file (filepath (player <player>) &key (wait nil))
  (let ((filename (if (pathnamep filepath)
                    (format nil "~A" filepath)
                    filepath)))
    (stop-play player)
    (with-slots (now-playing play-proc) player
      (setf play-proc
            (sb-ext:run-program "cvlc"
                                `("--play-and-exit" ,filename)
                                :wait wait :search t)
            now-playing filename))))

(defmethod play (playlist-idx (player <player>))
  (play-file (nth playlist-idx (playlist player)) player))


(defmethod play-playlist ((player <player>))
  (loop for file in (playlist player)
        do
        (play-file file player :wait t)))

ネットが無いなか模索しながら書きました。「とりあえず最低限の機能を、自分の環境だけで動作すれば良い汎用性はなくていいんだ」と決めて実装しました。
次にプレイリストの登録を自分で書くのは大変なので、なんとかゴソっともってくるようにしたいとおもい、簡易のファイラーを実装しました。

(ql:quickload :cl-fad)

(defpackage :cl-filer
  (:use :cl :cl-fad)
  (:export
    :<filer>
    :pwd
    :ls
    :show-ls
    :dir-list
    :show-dir-list
    :cd
    :up))

(in-package :cl-filer)

;;Utilities
(defun ls-directory (directory-pathname &optional (filter-fn #'identity))
  (loop for file in (list-directory directory-pathname)
        when (funcall filter-fn file)
        collect file))

(defun hidden-file-filter (pathname)
  (and (not (directory-pathname-p pathname))
       (not (string= "." 
                     (subseq (pathname-name pathname) 0 1)))))

(defclass <filer> ()
  ((cwd :initform (user-homedir-pathname) :initarg :cwd :accessor cwd)))

(defmethod pwd ((filer <filer>))
  (format t "~A~%" (cwd filer)))

(defmethod ls ((filer <filer>))
  (ls-directory (cwd filer) #'hidden-file-filter))

(defmethod show-ls ((filer <filer>))
  (let ((files (ls filer)))
    (loop for idx from 0 upto (1- (length files))
          do
          (format t "~A: ~A~%" idx (nth idx files)))))

(defmethod dir-list ((filer <filer>))
  (remove-if-not 
    #'directory-pathname-p
    (ls filer)))

(defmethod show-dir-list ((filer <filer>))
  (let ((directories (dir-list filer)))
    (loop for idx from 0 upto (1- (length directories))
          do
          (format t "~A: ~A~%" idx (nth idx directories)))))

(defmethod cd ((filer <filer>) &optional (dir-path-or-idx (user-homedir-pathname)))
  (let ((dir-path 
          (if (pathnamep dir-path-or-idx)
            dir-path-or-idx
            (nth dir-path-or-idx
                 (dir-list filer)))))
    (when (and dir-path (directory-pathname-p dir-path) (directory-exists-p dir-path))
      (setf (cwd filer) dir-path)
      (show-dir-list filer))))

(defmethod up ((filer <filer>))
  (let ((sb-cwd (sb-posix:getcwd)))
    (sb-posix:chdir (cwd filer))
    (sb-posix:chdir "..")
    (cd filer (pathname (sb-posix:getcwd)))
    (sb-posix:chdir sb-cwd)))

こちらも、処理系決めうちにするという暴挙にでてますが、まぁこの3日だけまずは動作すれば良いという事にして適当に作成しています。これで

(defvar *player* (make-instance '<player>))
(defvar *filer* (make-instance '<filer>))
;; Filer で適当なディレクトリにcd
(load-playlist (ls *filer*) *player*)
(show-playlist *player*)

として、プレーヤーにプレイリストを登録できます。
同様の昨日をもったプログラムがあったりvlcのオプションでできるぞ、とかあるのかもしれませんが、そういった前知識がなかったもので、自作するという事になりました。
色々と考える事になった3日間でした。