Skip to content

Commit e33e9dd

Browse files
committed
Initial commit ✔️
1 parent 57a0fd0 commit e33e9dd

File tree

7 files changed

+319
-50
lines changed

7 files changed

+319
-50
lines changed

LICENSE

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2018 The Python Packaging Authority
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is
8+
furnished to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19+
SOFTWARE.

README.md

Lines changed: 48 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,48 @@
1-
# musicfp
2-
**A terminal based media player for programmers**
3-
4-
------------
5-
6-
## Install
7-
8-
![installing](assets/install.png)
9-
10-
------------
11-
12-
## Examples
13-
14-
### Playing all songs in a direstory
15-
16-
> #### Windows
17-
18-
> ![playing all songs in windows](assets/windows.png)
19-
20-
> #### macOS / Linux
21-
22-
> ![playing all songs in macOS / linux](assets/linux.png)
23-
24-
### Playing a single song in a directory
25-
26-
> #### Windows
27-
28-
> ![playing single song in windows](assets/single_windows.png)
29-
30-
> #### macOS / Linux
31-
32-
> ![playing single song in macOS / linux](assets/single_linux.png)
33-
34-
------------
35-
36-
## Usage
37-
38-
> ![usage](assets/usage.png)
39-
40-
### Playback controls
41-
42-
> ![playback usage](assets/usage_playback.png)
43-
44-
------------
45-
46-
## Contributing
47-
48-
Contributions, issues and feature requests are welcome!
49-
Feel free to check [Bug Tracker](https://github.com/SatvikVirmani/musicfp/issues "issues") page.
50-
To submit improvements or features check [Pull Requests](https://github.com/SatvikVirmani/musicfp/pulls "Pull Requests")
1+
# musicfp
2+
**A terminal based media player for programmers**
3+
4+
------------
5+
6+
## Install
7+
8+
![installing](assets/install.png)
9+
10+
------------
11+
12+
## Examples
13+
14+
### Playing all songs in a direstory
15+
16+
> #### Windows
17+
18+
> ![playing all songs in windows](assets/windows.png)
19+
20+
> #### macOS / Linux
21+
22+
> ![playing all songs in macOS / linux](assets/linux.png)
23+
24+
### Playing a single song in a directory
25+
26+
> #### Windows
27+
28+
> ![playing single song in windows](assets/single_windows.png)
29+
30+
> #### macOS / Linux
31+
32+
> ![playing single song in macOS / linux](assets/single_linux.png)
33+
34+
------------
35+
36+
## Usage
37+
38+
> ![usage](assets/usage.png)
39+
40+
### Playback controls
41+
42+
> ![playback usage](assets/usage_playback.png)
43+
44+
------------
45+
46+
## Contributing
47+
48+
Contributions, issues and feature requests are welcome!. Feel free to check [Bug Tracker](https://github.com/SatvikVirmani/musicfp/issues "issues") page. To submit improvements or features check [Pull Requests](https://github.com/SatvikVirmani/musicfp/pulls "Pull Requests")

pyproject.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[build-system]
2+
requires = [
3+
"setuptools>=42",
4+
"wheel"
5+
]
6+
build-backend = "setuptools.build_meta"

setup.cfg

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
[metadata]
2+
name = musicfp
3+
version = 0.0.2
4+
author = Satvik Virmani
5+
author_email = virmanisatvik01@gmail.com
6+
description = A terminal based media player for programmers
7+
long_description = file: README.md
8+
long_description_content_type = text/markdown
9+
url = https://github.com/SatvikVirmani/musicfp
10+
project_urls =
11+
Bug Tracker = https://github.com/SatvikVirmani/musicfp/issues
12+
classifiers =
13+
Programming Language :: Python :: 3,
14+
Development Status :: 5 - Production/Stable,
15+
License :: OSI Approved :: MIT License,
16+
Operating System :: OS Independent,
17+
Topic :: Multimedia :: Sound/Audio
18+
19+
[options]
20+
package_dir =
21+
= src
22+
packages = find:musicfp
23+
python_requires = >=3.0
24+
install_requires = {python-vlc}
25+
26+
[options.entry_points]
27+
console_scripts =
28+
musicfp = musicfp.__main__:main
29+
30+
[options.packages.find]
31+
where = src

setup.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import setuptools
2+
3+
with open("README.md", "r", encoding="utf-8") as fh:
4+
long_description = fh.read()
5+
6+
setuptools.setup(
7+
name="musicfp",
8+
version="0.0.2",
9+
author="Satvik Virmani",
10+
author_email="virmanisatvik01@gmail.com",
11+
description="A terminal based media player for programmers",
12+
long_description=long_description,
13+
long_description_content_type="text/markdown",
14+
url="https://github.com/SatvikVirmani/musicfp",
15+
project_urls={
16+
"Bug Tracker": "https://github.com/SatvikVirmani/musicfp/issues",
17+
},
18+
classifiers=[
19+
"Programming Language :: Python :: 3",
20+
"Development Status :: 5 - Production/Stable",
21+
"License :: OSI Approved :: MIT License",
22+
"Operating System :: OS Independent",
23+
"Topic :: Multimedia :: Sound/Audio"
24+
],
25+
package_dir={"": "src"},
26+
packages=["musicfp"],
27+
python_requires=">=3.0",
28+
install_requires=[
29+
'python-vlc'
30+
],
31+
entry_points='''
32+
[console_scripts]
33+
musicfp=musicfp.__main__:main
34+
''',
35+
)

src/musicfp/__init__.py

Whitespace-only changes.

src/musicfp/__main__.py

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import argparse, os, sys, vlc, random
2+
from pathlib import Path
3+
from threading import Thread
4+
5+
parser = argparse.ArgumentParser(prog="musicfp", description="A terminal based media player for programmers")
6+
parser.add_argument(
7+
"path", metavar="path", type=str, help="path to directory containing file(s)"
8+
)
9+
parser.add_argument(
10+
"-s", "--shuffle", action="store_true", help="enable shuffling of songs"
11+
)
12+
13+
in_player_help_single = """
14+
skip skips playing song
15+
pause pauses/resumes playing song
16+
vol[vol] sets the volume to [vol]% eg. vol75 -sets volume to 75%
17+
quit quits the program
18+
19+
help displays usage of all commands
20+
"""
21+
22+
in_player_help_multiple = """
23+
pause pauses/resumes playing song
24+
next plays next song
25+
previous plays previous song
26+
vol[vol] sets the volume to [vol]% eg. vol75 -sets volume to 75%
27+
quit quits the program
28+
29+
help displays usage of all commands
30+
"""
31+
32+
33+
class MultiplePlayer:
34+
def __init__(self, path, shuffle):
35+
self.player = vlc.MediaListPlayer()
36+
self.list = vlc.MediaList()
37+
self.player.get_media_player().audio_set_volume(100)
38+
self.path = path
39+
self.shuffle = shuffle
40+
41+
def asyncInput(self):
42+
print(
43+
"Playing all songs from directory:",
44+
self.path,
45+
"with shuffle",
46+
("OFF", "ON")[self.shuffle],
47+
)
48+
while True:
49+
command = input(">> ")
50+
if command == "quit":
51+
self.player.stop()
52+
break
53+
elif command.startswith("vol"):
54+
volume = command.strip("vol")
55+
self.player.get_media_player().audio_set_volume(int(volume))
56+
print("Volume set to ", volume, "%")
57+
elif command == "next":
58+
self.player.next()
59+
elif command == "previous":
60+
self.player.previous()
61+
elif command == "pause":
62+
self.player.pause()
63+
print("Paused")
64+
elif command == "help":
65+
print(in_player_help_multiple)
66+
else:
67+
print("Invalid Command\nType help to view all available commands")
68+
69+
def startProcessing(self):
70+
formats = [".m4a", ".flac", ".mp3", ".mp4", ".wav", ".wma", ".aac", ".mkv"]
71+
files = []
72+
for file in os.listdir(self.path):
73+
for format in formats:
74+
if file.endswith(format):
75+
files.append(self.path / file)
76+
break
77+
for i in range(files.__len__()):
78+
if self.shuffle:
79+
fileMRL = files[random.randint(0, len(files) - 1)]
80+
self.list.add_media(fileMRL)
81+
files.remove(fileMRL)
82+
else:
83+
fileMRL = files[i]
84+
self.list.add_media(fileMRL)
85+
self.player.set_media_list(self.list)
86+
self.player.play()
87+
88+
89+
def play_multiple(dirPath, shuffle):
90+
item = MultiplePlayer(dirPath, shuffle)
91+
thread_a = Thread(target=item.startProcessing)
92+
thread_a.start()
93+
thread_b = Thread(target=item.asyncInput)
94+
thread_b.start()
95+
thread_a.join()
96+
thread_b.join()
97+
98+
99+
class SinglePlayer:
100+
def __init__(self, file):
101+
self.instance = vlc.Instance()
102+
self.player = self.instance.media_player_new()
103+
self.player.audio_set_volume(100)
104+
self.media = vlc.Media(file)
105+
106+
def asyncInput(self):
107+
self.media.parse()
108+
print("Playing", self.media.get_meta(0), 'from "', self.media.get_meta(4), '"')
109+
while True:
110+
command = input(">> ")
111+
if command == "skip":
112+
self.player.stop()
113+
print("Skipped")
114+
elif command == "quit":
115+
self.player.stop()
116+
break
117+
elif command.startswith("vol"):
118+
volume = command.strip("vol")
119+
self.player.audio_set_volume(int(volume))
120+
print("Volume set to ", volume, "%")
121+
elif command == "pause":
122+
self.player.pause()
123+
print("Paused")
124+
elif command == "resume":
125+
self.player.pause()
126+
print("Resumed")
127+
elif command == "repeat":
128+
self.player.stop()
129+
print("Repeated")
130+
self.player.play()
131+
elif command == "help":
132+
print(in_player_help_single)
133+
else:
134+
print("Invalid Command\nType help to view all available commands")
135+
136+
def startProcessing(self):
137+
self.player.set_media(self.media)
138+
self.player.play()
139+
140+
141+
def play_single(filePath):
142+
item = SinglePlayer(filePath)
143+
thread_a = Thread(target=item.startProcessing)
144+
thread_a.start()
145+
thread_b = Thread(target=item.asyncInput)
146+
thread_b.start()
147+
thread_a.join()
148+
thread_b.join()
149+
150+
151+
if len(sys.argv) == 1:
152+
parser.print_help()
153+
sys.exit()
154+
elif len(sys.argv) >= 2:
155+
args = parser.parse_args()
156+
157+
if os.path.isdir(args.path):
158+
path = args.path
159+
elif os.path.isfile(args.path):
160+
path = args.path
161+
else:
162+
if args.path == "current":
163+
path = os.getcwd()
164+
else:
165+
print("Directory does not exist")
166+
sys.exit()
167+
168+
do_shuffle = args.shuffle
169+
else:
170+
parser.print_help()
171+
172+
def main():
173+
formats = [".m4a", ".flac", ".mp3", ".mp4", ".wav", ".wma", ".aac", ".mkv"]
174+
if str(Path(path).suffix) in formats:
175+
play_single(Path(path))
176+
else:
177+
play_multiple(Path(path), do_shuffle)
178+
179+
if __name__ == "__main__":
180+
main()

0 commit comments

Comments
 (0)