python-vlc-player 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_vlc_player/__init__.py +0 -0
- python_vlc_player/player.py +258 -0
- python_vlc_player-0.0.1.dist-info/METADATA +13 -0
- python_vlc_player-0.0.1.dist-info/RECORD +7 -0
- python_vlc_player-0.0.1.dist-info/WHEEL +5 -0
- python_vlc_player-0.0.1.dist-info/licenses/LICENCE +19 -0
- python_vlc_player-0.0.1.dist-info/top_level.txt +1 -0
|
File without changes
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import vlc
|
|
2
|
+
from tkinter import *
|
|
3
|
+
import tkinter.ttk as ttk
|
|
4
|
+
from tkinter import filedialog, messagebox
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
import threading
|
|
8
|
+
from time import sleep
|
|
9
|
+
|
|
10
|
+
class Media_Player:
|
|
11
|
+
def __init__(self , app):
|
|
12
|
+
|
|
13
|
+
self.instance = vlc.Instance()
|
|
14
|
+
self.player = self.instance.media_player_new()
|
|
15
|
+
|
|
16
|
+
self.is_paused = False
|
|
17
|
+
self.media = None
|
|
18
|
+
self.user_dragging = False
|
|
19
|
+
self.is_fullscreen = False
|
|
20
|
+
|
|
21
|
+
self.filename = ''
|
|
22
|
+
|
|
23
|
+
self.update_thread_started = False
|
|
24
|
+
|
|
25
|
+
self.app = app
|
|
26
|
+
|
|
27
|
+
self.app.minsize(900, 500)
|
|
28
|
+
self.app.geometry('1100x600')
|
|
29
|
+
self.app.title('video-player')
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
self.video_output = Frame(self.app, bg='black')
|
|
33
|
+
self.video_output.pack(fill=BOTH, expand=True)
|
|
34
|
+
|
|
35
|
+
self.cover_overlay = Label(self.video_output, bg="black")
|
|
36
|
+
self.cover_overlay.place(relx=0.5, rely=0.5, anchor=CENTER)
|
|
37
|
+
|
|
38
|
+
self.time_frame = Frame(app)
|
|
39
|
+
self.time_frame.pack()
|
|
40
|
+
|
|
41
|
+
self.slidet = ttk.Scale(self.time_frame, from_=0,to=1000, length=1650)
|
|
42
|
+
self.slidet.pack()
|
|
43
|
+
|
|
44
|
+
self.slidet.bind("<ButtonPress-1>", self.start_drag)
|
|
45
|
+
self.slidet.bind("<ButtonRelease-1>", self.stop_drag)
|
|
46
|
+
|
|
47
|
+
self.contoroll_frame = Frame(self.app, bg='gray')
|
|
48
|
+
self.contoroll_frame.pack(side=LEFT)
|
|
49
|
+
|
|
50
|
+
self.open_video = ttk.Button(self.contoroll_frame, text='Open', command=self.open_file)
|
|
51
|
+
self.open_video.pack(side=LEFT)
|
|
52
|
+
|
|
53
|
+
self.play_video = ttk.Button(self.contoroll_frame, text='Play', state=DISABLED, command=self.play_pause)
|
|
54
|
+
self.play_video.pack(side=LEFT)
|
|
55
|
+
|
|
56
|
+
self.stop_video = ttk.Button(self.contoroll_frame, text='Stop', state=DISABLED, command=self.stop)
|
|
57
|
+
self.stop_video.pack(side=LEFT)
|
|
58
|
+
|
|
59
|
+
self.screenshot = ttk.Button(self.contoroll_frame, text="Screenshot", command=self.take_snapshot, state=DISABLED)
|
|
60
|
+
self.screenshot.pack(side=LEFT)
|
|
61
|
+
|
|
62
|
+
ttk.Label(self.contoroll_frame, text='Speed').pack(side=LEFT,pady=5, padx=5)
|
|
63
|
+
|
|
64
|
+
self.speed_var = DoubleVar(value=1.0)
|
|
65
|
+
|
|
66
|
+
self.speed_scalle = ttk.Scale(self.contoroll_frame, from_=0.5, to=2.0, length=200, variable=self.speed_var, command=self.change_speed)
|
|
67
|
+
self.speed_scalle.pack(side=LEFT)
|
|
68
|
+
|
|
69
|
+
ttk.Label(self.contoroll_frame, text="Vol").pack(side=LEFT,pady=5, padx=5)
|
|
70
|
+
|
|
71
|
+
self.sond_var = DoubleVar(value=40)
|
|
72
|
+
|
|
73
|
+
self.sond_scalle = ttk.Scale(self.contoroll_frame, from_=0, to=200, length=200, command=self.on_volume_change, variable=self.sond_var)
|
|
74
|
+
self.sond_scalle.pack(side=LEFT)
|
|
75
|
+
|
|
76
|
+
self.player.audio_set_volume(40)
|
|
77
|
+
|
|
78
|
+
self.time_label = Label(self.app, text='00:00 / 00:00')
|
|
79
|
+
self.time_label.pack(side=LEFT,pady=5, padx=5)
|
|
80
|
+
|
|
81
|
+
self.status_label = ttk.Label(self.contoroll_frame, text='No media loaded')
|
|
82
|
+
self.status_label.pack(side=LEFT,pady=5, padx=5)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def seek_relative(self, seconds):
|
|
86
|
+
if not self.player.get_media():
|
|
87
|
+
return
|
|
88
|
+
current = self.player.get_time()
|
|
89
|
+
new_time = max(0, current + seconds * 1000)
|
|
90
|
+
self.player.set_time(int(new_time))
|
|
91
|
+
|
|
92
|
+
def change_volume_relative(self, delta):
|
|
93
|
+
current = self.player.audio_get_volume()
|
|
94
|
+
if current == -1:
|
|
95
|
+
current = 0
|
|
96
|
+
new_vol = max(0, min(200, current + delta))
|
|
97
|
+
self.sond_scalle.set(new_vol)
|
|
98
|
+
self.player.audio_set_volume(new_vol)
|
|
99
|
+
|
|
100
|
+
def exit_fullscreen(self):
|
|
101
|
+
if self.is_fullscreen:
|
|
102
|
+
self.is_fullscreen = False
|
|
103
|
+
self.app.attributes("-fullscreen", False)
|
|
104
|
+
|
|
105
|
+
def toggle_fullscreen(self):
|
|
106
|
+
self.is_fullscreen = not self.is_fullscreen
|
|
107
|
+
self.app.attributes("-fullscreen", self.is_fullscreen)
|
|
108
|
+
|
|
109
|
+
def open_file(self):
|
|
110
|
+
self.player.stop()
|
|
111
|
+
self.slidet.set(0)
|
|
112
|
+
filetypes = [
|
|
113
|
+
("Video files", "*.mp4 *.mkv *.avi *.mov *.flv *.wmv"),
|
|
114
|
+
("All files", "*.*"),
|
|
115
|
+
('Audio files', '*.mp3 *.wma *.aac *.ogg *.ra *.m4a')
|
|
116
|
+
]
|
|
117
|
+
self.filename = filedialog.askopenfilename(
|
|
118
|
+
title="📂",
|
|
119
|
+
filetypes=filetypes
|
|
120
|
+
)
|
|
121
|
+
if not self.filename:
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
ext = os.path.splitext(self.filename)[1].lower()
|
|
125
|
+
|
|
126
|
+
if not os.path.exists(self.filename):
|
|
127
|
+
messagebox.showerror("خطا", "فایل پیدا نشد!")
|
|
128
|
+
return
|
|
129
|
+
try:
|
|
130
|
+
|
|
131
|
+
# ساخت رسانه جدید و اتصال به پلیر
|
|
132
|
+
media = self.instance.media_new(self.filename)
|
|
133
|
+
self.player.set_media(media)
|
|
134
|
+
|
|
135
|
+
self._set_video_output()
|
|
136
|
+
|
|
137
|
+
# بروزرسانی وضعیت
|
|
138
|
+
self.status_label.config(text=os.path.basename(self.filename))
|
|
139
|
+
self.play_video.config(state=NORMAL, text="Pause")
|
|
140
|
+
self.stop_video.config(state=NORMAL)
|
|
141
|
+
self.screenshot.config(state=NORMAL)
|
|
142
|
+
self.is_paused = False
|
|
143
|
+
# شروع پخش
|
|
144
|
+
self.start_update_thread()
|
|
145
|
+
|
|
146
|
+
#if ext in [".mp3", ".m4a", ".aac", ".ogg", ".wma"]:
|
|
147
|
+
# self.show_audio_cover(filename)
|
|
148
|
+
#else:
|
|
149
|
+
# self.hide_cover()
|
|
150
|
+
|
|
151
|
+
self.player.play()
|
|
152
|
+
|
|
153
|
+
except Exception as e:
|
|
154
|
+
messagebox.showerror("خطا در پخش", str(e))
|
|
155
|
+
|
|
156
|
+
def _set_video_output(self):
|
|
157
|
+
if not self.video_output.winfo_ismapped():
|
|
158
|
+
return
|
|
159
|
+
handle = self.video_output.winfo_id()
|
|
160
|
+
if sys.platform.startswith("win"):
|
|
161
|
+
self.player.set_hwnd(handle)
|
|
162
|
+
|
|
163
|
+
else:
|
|
164
|
+
if sys.platform == "darwin":
|
|
165
|
+
from ctypes import c_void_p
|
|
166
|
+
self.player.set_nsobject(c_void_p(handle))
|
|
167
|
+
else:
|
|
168
|
+
self.player.set_xwindow(handle)
|
|
169
|
+
|
|
170
|
+
def play_pause(self):
|
|
171
|
+
if self.player.is_playing():
|
|
172
|
+
self.player.pause()
|
|
173
|
+
self.play_video.config(text="Play")
|
|
174
|
+
self.is_paused = True
|
|
175
|
+
self.start_update_thread()
|
|
176
|
+
else:
|
|
177
|
+
state = self.player.get_state()
|
|
178
|
+
if state in (vlc.State.Ended, vlc.State.Stopped):
|
|
179
|
+
self.player.stop()
|
|
180
|
+
self.player.play()
|
|
181
|
+
else:
|
|
182
|
+
self.player.play()
|
|
183
|
+
self.play_video.config(text="Pause")
|
|
184
|
+
self.is_paused = False
|
|
185
|
+
|
|
186
|
+
def stop(self):
|
|
187
|
+
#if media is None:
|
|
188
|
+
# return
|
|
189
|
+
self.player.stop()
|
|
190
|
+
self.play_video.config(text="Play")
|
|
191
|
+
self.is_paused = False
|
|
192
|
+
self.slidet.set(0)
|
|
193
|
+
|
|
194
|
+
def on_volume_change(self, event):
|
|
195
|
+
try:
|
|
196
|
+
vol = int(float(event))
|
|
197
|
+
self.player.audio_set_volume(vol)
|
|
198
|
+
except:
|
|
199
|
+
pass
|
|
200
|
+
|
|
201
|
+
def change_speed(self, event):
|
|
202
|
+
self.player.set_rate(float(event))
|
|
203
|
+
|
|
204
|
+
def start_drag(self, event):
|
|
205
|
+
self.user_dragging = True
|
|
206
|
+
|
|
207
|
+
def stop_drag(self, event):
|
|
208
|
+
if self.filename == '':
|
|
209
|
+
self.slidet.set(0)
|
|
210
|
+
else:
|
|
211
|
+
self.user_dragging = False
|
|
212
|
+
self.new_position = self.slidet.get() / 1000.0
|
|
213
|
+
self.player.set_position(self.new_position)
|
|
214
|
+
|
|
215
|
+
def update_thread(self):
|
|
216
|
+
while True:
|
|
217
|
+
sleep(0.5)
|
|
218
|
+
try:
|
|
219
|
+
if not self.user_dragging:
|
|
220
|
+
self.pos = self.player.get_position()
|
|
221
|
+
self.current_time = self.player.get_time() / 1000
|
|
222
|
+
self.app.after(0, self.update_ui, self.pos, self.current_time)
|
|
223
|
+
except Exception:
|
|
224
|
+
break
|
|
225
|
+
|
|
226
|
+
def update_ui(self, pos, current_time):
|
|
227
|
+
if pos > 0:
|
|
228
|
+
duration = int(self.player.get_length()/1000)
|
|
229
|
+
self.slidet.set(int(pos * 1000))
|
|
230
|
+
|
|
231
|
+
mins, secs = divmod(int(current_time), 60)
|
|
232
|
+
total_mins, total_secs = divmod(int(duration), 60)
|
|
233
|
+
|
|
234
|
+
self.time_label.config(text=f"{mins:02}:{secs:02} / {total_mins:02}:{total_secs:02}")
|
|
235
|
+
|
|
236
|
+
def take_snapshot(self):
|
|
237
|
+
self.player.video_take_snapshot(0, "snapshot.png", 0, 0)
|
|
238
|
+
|
|
239
|
+
def start_update_thread(self):
|
|
240
|
+
if self.update_thread_started:
|
|
241
|
+
return
|
|
242
|
+
|
|
243
|
+
self.update_thread_started = True
|
|
244
|
+
|
|
245
|
+
threading.Thread(
|
|
246
|
+
target=self.update_thread,
|
|
247
|
+
daemon=True
|
|
248
|
+
).start()
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
if __name__ == '__main__':
|
|
254
|
+
root = Tk()
|
|
255
|
+
|
|
256
|
+
player = Media_Player(root)
|
|
257
|
+
|
|
258
|
+
root.mainloop()
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python_vlc_player
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A packege to make a player in python
|
|
5
|
+
Author: Edalat
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.9
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENCE
|
|
12
|
+
Requires-Dist: python-vlc
|
|
13
|
+
Dynamic: license-file
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
python_vlc_player/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
python_vlc_player/player.py,sha256=02-7EtXE5PpTYOA8k3yIqUhLR9noj3yxwEuV2NV9wKI,8494
|
|
3
|
+
python_vlc_player-0.0.1.dist-info/licenses/LICENCE,sha256=PmkEOcF-Jq2TXaLSrv8OTz3jB4Ci1AwWnL4Hs-gBE3o,1084
|
|
4
|
+
python_vlc_player-0.0.1.dist-info/METADATA,sha256=JVJMk4z_cvu8Ns-5DhjzMX-P1qL2e1vg3MSkFP7W5Yw,387
|
|
5
|
+
python_vlc_player-0.0.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
6
|
+
python_vlc_player-0.0.1.dist-info/top_level.txt,sha256=TZ3NdvC7vFH4oIVH47VtauF81tM8eGZbD46JHmF0P14,18
|
|
7
|
+
python_vlc_player-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2018 mohamad reza amiri noor
|
|
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.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
python_vlc_player
|