for文との格闘
タイトルの箇所
戻る(一つ前の曲を再生する)
えー、僕は最近自作音楽プレイヤーを作ってます
音楽プレイヤーと言ってもとても単純なやつです
①コマンドライン引数からファイルパス取得
(①で取得したパスがファイルだった場合)
②そのまま再生
(①で取得したパスがディレクトリだった場合)
②glob.glob()でその中身を取得
③②の戻り値をfor文で回して順に再生
……というようなプログラムです
しかし、これだけではホントに単純過ぎるのでせめて「曲をスキップ・戻る、ランダム再生」くらいの機能は付けようと思いました
曲をスキップ
これは簡単にできました
#coding: utf-8 import pygame import os from mutagen.mp3 import MP3 from timeout_decorator import timeout, TimeoutError def main(argv): if os.path.isfile(argv[1]): play(argv[1]) else: play(glob.glob(os.path.join(*[argv[1], '*']))) def play(path): for f in path: pygame.mixer.init() pygame.mixer.music.load(f) length = MP3(f).info.length pygame.mixer.music.play() result settings(length) if result == None: pygame.mixer.music.stop() continue def settings(sec): @timeout(sec) def option(): while True: opt = sys.stdin.read(1) if opt == 'n': return try: return option() except TimeoutError: return if __name__ == '__main__': main(sys.argv[1])
音声を再生したあと、setting関数を呼び出します。
そしてoption関数のタイムアウト時間を音源の長さと同じに設定して、option関数を呼び出します
nが入力されたら現在の曲をスキップして次の曲を流します
音源が再生し終わった(つまりoption関数がタイムアウトした)らまた次の音声を再生します。
戻る(一つ前の曲を再生する)
これにつまずきました
だってfor文中に要素の取り出しを一個前に戻すなんてコード知りませんし調べても出てこないんですもん
諦めそうになった
かれこれ30分この問題と格闘した結果……
#coding: utf-8 import pygame import os from mutagen.mp3 import MP3 from timeout_decorator import timeout, TimeoutError def main(argv): if os.path.isfile(argv[1]): play(argv[1]) else: play(glob.glob(os.path.join(*[argv[1], '*']))) def play(path, num): for n, f in enumerate(path): if n<num: continue pygame.mixer.init() pygame.mixer.music.load(f) length = MP3(f).info.length pygame.mixer.music.play() result = settings(length) if result == None: pygame.mixer.music.stop() elif result == 'back': pygame.mixer.music.stop() play(path, n-1) def settings(sec): @timeout(sec) def option(): opt = sys.stdin.read(1) if opt == 'n': return elif opt == 'b': return 'back' try: return option() except TimeoutError: return if __name__ == '__main__': main(sys.argv[1], 0)
play関数の引数を一つ増やしました
こうすることでインデックスがnum未満のやつはスキップさせることができました(最初はnumの値が0なので何もスキップしない)
これを早く思いつかなかった自分を殴りたい
ランダム再生
#coding: utf-8 import pygame import os import random from mutagen.mp3 import MP3 from timeout_decorator import timeout, TimeoutError def main(argv): if os.path.isfile(argv[1]): play(argv[1]) else: play(random.shuffle(glob.glob(os.path.join(*[argv[1], '*'])))) def play(path, num): for n, f in enumerate(path): if n<num: continue pygame.mixer.init() pygame.mixer.music.load(f) length = MP3(f).info.length pygame.mixer.music.play() result = settings(length) if result == None: pygame.mixer.music.stop() elif result == 'back': pygame.mixer.music.stop() play(path, n-1) def settings(sec): @timeout(sec) def option(): opt = sys.stdin.read(1) if opt == 'n': return elif opt == 'b': return 'back' try: return option() except TimeoutError: return if __name__ == '__main__': main(sys.argv[1], 0)
play関数に渡すリストをシャッフルしてみました
最初はrandom.randintでインデックス番号生成しようかなぁなんて考えてたのですが、調べてる途中random.shuffle関数様と出会いました
このお方のおかげでランダム再生の実装が簡単に終わった
おまけ
「いちいちn押してEnter押すの面倒くさいなー」と思ってEnter押さなくても勝手に標準入力受け取ってくれる魔法のモジュールを探していました
そしたら見つかりました、「termios」というものを!!
#coding: utf-8 import pygame import os import random import termios from mutagen.mp3 import MP3 from timeout_decorator import timeout, TimeoutError def main(argv): if os.path.isfile(argv[1]): play(argv[1]) else: play(random.shuffle(glob.glob(os.path.join(*[argv[1], '*'])))) def play(path, num): for n, f in enumerate(path): if n<num: continue pygame.mixer.init() pygame.mixer.music.load(f) length = MP3(f).info.length pygame.mixer.music.play() result = settings(length) if result == None: pygame.mixer.music.stop() elif result == 'back': pygame.mixer.music.stop() play(path, n-1) def settings(sec): @timeout(sec) def option(): fd = sys.stdin.fileno() old = termios.tcgetattr(fd) new = termios.tcgetattr(fd) new[3] &= ~termios.ICANON new[3] &= ~termios.ECHO try: termios.tcsetattr(fd, termios.TCSANOW, new) opt = sys.stdin.read(1) finally: termios.tcsetattr(fd, termios.TCSANOW, old) if opt == 'n': return elif opt == 'b': return 'back' try: return option() except TimeoutError: return if __name__ == '__main__': main(sys.argv[1], 0)
どうやらtermiosを使って設定を弄るようです
入力も出力されないっぽい
これはいいねぇ
参考:
https://qiita.com/tortuepin/items/9ede6ca603ddc74f91ba
あと追加したい機能
- プレイリスト表示(簡単そう)
- ループ再生
- 一時停止
ただソースコード置くだけみたいな記事になってしまってすみません