easympv 1.4.0__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.
Files changed (77) hide show
  1. easympv-1.4.0.dist-info/METADATA +147 -0
  2. easympv-1.4.0.dist-info/RECORD +77 -0
  3. easympv-1.4.0.dist-info/WHEEL +5 -0
  4. easympv-1.4.0.dist-info/entry_points.txt +2 -0
  5. easympv-1.4.0.dist-info/top_level.txt +1 -0
  6. easyplayer/AudioPlay.py +210 -0
  7. easyplayer/EasyPlayer.py +1456 -0
  8. easyplayer/FFMPEGTools.py +1420 -0
  9. easyplayer/Playlist.py +281 -0
  10. easyplayer/QtTools.py +59 -0
  11. easyplayer/Slideshow.py +107 -0
  12. easyplayer/__init__.py +0 -0
  13. easyplayer/icons/Pictures-icon.png +0 -0
  14. easyplayer/icons/clear-all.png +0 -0
  15. easyplayer/icons/close-x.png +0 -0
  16. easyplayer/icons/easyPlay.png +0 -0
  17. easyplayer/icons/easyPlay.svg +121 -0
  18. easyplayer/icons/film-clapper.png +0 -0
  19. easyplayer/icons/flatdark/fullscreen.png +65 -0
  20. easyplayer/icons/flatdark/goto.svg +72 -0
  21. easyplayer/icons/flatdark/info.svg +76 -0
  22. easyplayer/icons/flatdark/mute.svg +73 -0
  23. easyplayer/icons/flatdark/newList.svg +62 -0
  24. easyplayer/icons/flatdark/open.svg +51 -0
  25. easyplayer/icons/flatdark/pause.svg +48 -0
  26. easyplayer/icons/flatdark/play.svg +49 -0
  27. easyplayer/icons/flatdark/remove.svg +50 -0
  28. easyplayer/icons/flatdark/remove_all.svg +88 -0
  29. easyplayer/icons/flatdark/save.svg +66 -0
  30. easyplayer/icons/flatdark/screenshot.svg +44 -0
  31. easyplayer/icons/flatdark/settings.svg +49 -0
  32. easyplayer/icons/flatdark/sound.svg +67 -0
  33. easyplayer/icons/flatdark/splitVertical.svg +1 -0
  34. easyplayer/icons/flatdark/start-cut.svg +7 -0
  35. easyplayer/icons/flatdark/stop-cut.svg +7 -0
  36. easyplayer/icons/flaticons/fullscreen.png +0 -0
  37. easyplayer/icons/flaticons/goto.svg +7 -0
  38. easyplayer/icons/flaticons/info.svg +9 -0
  39. easyplayer/icons/flaticons/mute.svg +13 -0
  40. easyplayer/icons/flaticons/newList.svg +8 -0
  41. easyplayer/icons/flaticons/open.svg +4 -0
  42. easyplayer/icons/flaticons/pause.svg +4 -0
  43. easyplayer/icons/flaticons/play.svg +46 -0
  44. easyplayer/icons/flaticons/remove.svg +4 -0
  45. easyplayer/icons/flaticons/remove_all.svg +12 -0
  46. easyplayer/icons/flaticons/save.svg +8 -0
  47. easyplayer/icons/flaticons/screenshot.svg +8 -0
  48. easyplayer/icons/flaticons/settings.svg +4 -0
  49. easyplayer/icons/flaticons/sound.svg +12 -0
  50. easyplayer/icons/flaticons/splitVertical.svg +1 -0
  51. easyplayer/icons/flaticons/start-cut.svg +7 -0
  52. easyplayer/icons/flaticons/stop-cut.svg +7 -0
  53. easyplayer/icons/fullscreen.png +0 -0
  54. easyplayer/icons/go-next.png +0 -0
  55. easyplayer/icons/icomap.json +74 -0
  56. easyplayer/icons/info.png +0 -0
  57. easyplayer/icons/langflags.png +0 -0
  58. easyplayer/icons/license.txt +6 -0
  59. easyplayer/icons/loadfile.png +0 -0
  60. easyplayer/icons/movie-icon.png +0 -0
  61. easyplayer/icons/newList.png +0 -0
  62. easyplayer/icons/next.png +0 -0
  63. easyplayer/icons/pause.png +0 -0
  64. easyplayer/icons/play.png +0 -0
  65. easyplayer/icons/previous.png +0 -0
  66. easyplayer/icons/save-as-icon.png +0 -0
  67. easyplayer/icons/screenshot.png +0 -0
  68. easyplayer/icons/settings.png +0 -0
  69. easyplayer/icons/speaker-high.png +0 -0
  70. easyplayer/icons/speaker-muted.png +0 -0
  71. easyplayer/icons/splitVertical.png +0 -0
  72. easyplayer/icons/start-icon.png +0 -0
  73. easyplayer/icons/stop-red-icon.png +0 -0
  74. easyplayer/icons/video_clapper.png +0 -0
  75. easyplayer/icons/window-close.png +0 -0
  76. easyplayer/lib/__init__.py +0 -0
  77. easyplayer/lib/mpv.py +2206 -0
@@ -0,0 +1,147 @@
1
+ Metadata-Version: 2.4
2
+ Name: easympv
3
+ Version: 1.4.0
4
+ Summary: Simple video and audio player based on mpv
5
+ License: GPL-2.0-or-later
6
+ Project-URL: Homepage, https://github.com/kanehekili/EasyPlayer
7
+ Requires-Python: >=3.9
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: PyQt6
10
+
11
+ # EasyPlayer
12
+ Version 1.4.0
13
+
14
+
15
+ A simple video and audio player based on mpv and QT6 . It is a spin off of my VideoCut app. It handles pictures, plays videos and audio files.
16
+
17
+ ![Screenshot](https://raw.githubusercontent.com/kanehekili/EasyPlayer/main/easyplayer.png)
18
+
19
+ Configurable Spectrum Analyzer:
20
+
21
+ ![Screenshot](https://raw.githubusercontent.com/kanehekili/EasyPlayer/main/spectrum.png)
22
+
23
+ ### Prerequisites
24
+ * Arch: python3, python-pillow and mpv
25
+ * Debian/Mint/Ubuntu: python3 python3-pil libmpv2 (or libmpv1) (no-recommends)
26
+ * Ubuntu 26.04 needs additionally qt6-svg-plugins
27
+ #not working for Ubuntu 18.4: libmpv - use python3-opencv instead
28
+ * Fedora: python3-pillow-qt and mpv-libs.x86_64
29
+ * ffmpeg > 3.X to 8.X
30
+ * python3-pyqt6
31
+
32
+ #### Set GTK Theme for this QT application
33
+ If you are running a DE with GTK/Gnome (as opposed to LXQT or KDE) you might set QT_QPA_PLATFORMTHEME:
34
+ * Depending on the distro and version this variable may be defined with one of:
35
+ * gtk2, qt6ct, fusion, gtk3
36
+ * Easyplayer will enforce "QT_QPA_PLATFORM=xcb" on Wayland for SSD decorations.
37
+ * On Ubuntu 26.04 you need to install qt6-gtk-platformtheme. This will get your GTK theme into any QT6 app.
38
+ * On Ubuntu(with libadwaita) use /etc/environment to add GTK_THEME=yourTheme to enforce a third party theme. (Hack)
39
+
40
+ ### Features
41
+ * Easyplayer supports wayland and orientation recognition (which mplayer does not).
42
+ * Has been tested with interlaced video and 4K
43
+ * Subtitles can be shown (settings)
44
+ * Playlist support
45
+ * Picture/image viewer (png, jpg, bmp, gif, webp, tiff)
46
+ * Slideshow with configurable timeout
47
+ * Flat and non flat icon set
48
+ * Language can be selected
49
+ * Supports an EQ-display for audio files - Some distros need to install python3-sounddevice via pip. (Not mandatory)
50
+ * Colors of the EQ display can be changed live via the settings dialog.
51
+ * Settings allows you to switch to software mode (old hardware & virtual environments)
52
+
53
+
54
+ ### Support for Qemu and old hardware:
55
+ * -v will use a virtual GL driver or software for rendering. (easyplayer -v)
56
+ * Can be set via the "Settings dialog - Software mode" as well.
57
+
58
+
59
+ #### Install via ppa on Linux Mint or Ubuntu (Mint 22.2, Ubuntu 22.04 and newer versions)
60
+ ```
61
+ sudo add-apt-repository ppa:jentiger-moratai/mediatools
62
+ sudo apt update
63
+ sudo apt install --no-install-recommends easyplayer
64
+ ```
65
+ (--no-install-recommends will install only what is required)
66
+ Select video and open it with "Open with ->EasyPlayer", oder via terminal "easyplayer"
67
+
68
+ Remove with:
69
+ `sudo apt remove easyplayer`
70
+
71
+ #### Install EasyPlayer via AUR (Arch Linux /Manjaro only)
72
+ * Use pamac or other GUI tools, search for "easyplayer" in AUR, click install
73
+ * Manually :
74
+ * Download [PKGBUILD ](https://aur.archlinux.org/cgit/aur.git/snapshot/easyplayer.tar.gz)
75
+ * unpack it and go into the "easyplayer" folder
76
+ * execute `makepkg -s`
77
+ * excute `sudo pacman -U easyplayer-1.x.x.x-1-x86_64.pkg.tar.zst`
78
+ * uninstall via `sudo pacman -Rs easyplayer`
79
+
80
+ Select video and open it with "Open with ->EasyPlayer", oder via terminal "easyplayer"
81
+
82
+
83
+ #### Install dependencies manually on Linux Mint or Ubuntu (tested from noble to resolute)
84
+ ```
85
+ sudo apt –no-install-recommends install python3-pyqt6 ffmpeg python3-pil libmpv2
86
+ ```
87
+
88
+ #### Install dependencies on Fedora
89
+ ```
90
+ sudo dnf python3-qt6 ffmpeg python3-pillow-qt mpv-libs.x86_64
91
+ ```
92
+
93
+ ### How to install with a terminal
94
+ * Install dependencies (see prerequisites)
95
+ * Download the easyplayer*.tar from the download link (see above)
96
+ * Extract it to a location that suits you.
97
+ * Open a terminal to execute the install.sh file inside the folder with sudo like `sudo ./install.sh`
98
+ * (if you are in the download directory - just an example)
99
+ * The app will be installed in /opt/easyplayer with a link to /usr/bin.
100
+ * The app should be appear in a menu or "Actvities"
101
+ * Can be openend by selecting a video file & Open with...
102
+ * In the terminal can be started via `easyplayer`
103
+ * python qt6, mpv and ffmpeg are required
104
+ * you may now remove that download directory.
105
+ * logs can be found in the user home ".config/EasyPlayer" folder
106
+
107
+ ### How to remove
108
+ * Open a terminal
109
+ * execute `sudo /opt/easyplayer/uninstall.sh`
110
+
111
+ ### Changes
112
+ 23.04.2026:
113
+ * Added slideshow features for pictures
114
+ * Improved scrolling while playing
115
+
116
+ 18.04.2026
117
+ * Remove outer border for fullscreen
118
+ * Picture/image support added to file dialog and MIME types
119
+ * Fix playlist errors
120
+
121
+ 30.03.2026
122
+ * Playlist support
123
+ * Fix scaled Xwayland desktops
124
+
125
+ 21.03.2026
126
+ * Support for virtual environments or slow hardware via SettingsDialog
127
+
128
+ 20.03.2026
129
+ * introducing "parec" for Spectrum EQ (Ubuntu)
130
+
131
+ 16.03.2026
132
+ * Configuration of Spectrum EQ
133
+ * Reviewed Pulseaudio dependencies
134
+ * Distro agnostic installation (Debian & Arch)
135
+
136
+ 12.03.2026
137
+ * Graphic EQ display for audio files
138
+
139
+ 09.03.2026
140
+ * Support for playlists and streams
141
+
142
+ 05.03.2026
143
+ * Hardened interlacing recognition, fixed interprocess communication
144
+
145
+ 26..12.2025
146
+ * Initial start
147
+
@@ -0,0 +1,77 @@
1
+ easyplayer/AudioPlay.py,sha256=4wniMy-hEZSxEwv8AUPvNu3VxovyGIlpIfA9pYjci1Y,7290
2
+ easyplayer/EasyPlayer.py,sha256=OeKFRFTaRPscOHWEIx84Rhwy-Eycg3cIgsdRIoW9nZk,56890
3
+ easyplayer/FFMPEGTools.py,sha256=TQimYgsFKIbiVNCY58cU-KoDoF8AV_sZOUo816vAsYM,46015
4
+ easyplayer/Playlist.py,sha256=n92qz6eUXAFfsOZAj2i4_StvvH8C-WX-obW9rxdDGAo,9104
5
+ easyplayer/QtTools.py,sha256=1vlJ1YF2pRzE8vzYksFFZ3xhUBiSF4vQQGBdnLKBotM,1863
6
+ easyplayer/Slideshow.py,sha256=CUtD80HVMTYKSvvmf1AKEPQRevLDqODzwjLXOm49Tys,3925
7
+ easyplayer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ easyplayer/icons/Pictures-icon.png,sha256=nRXcb0j4wffG8COCz_bH55wpe1-roagz_vtmYMBTX5o,31152
9
+ easyplayer/icons/clear-all.png,sha256=wvGLF-xR1NNlaTlYsvlBIbDO_muCO5BnixHsAWZT-pM,19751
10
+ easyplayer/icons/close-x.png,sha256=oCv28VjQgE-MeLTy0TTp5hjB9oGTIHFm4UsWDh67CtM,9925
11
+ easyplayer/icons/easyPlay.png,sha256=4kdLxFKybPaNEI5BcEIXLH5QysmuKMhhB3e4iNfhWHQ,57948
12
+ easyplayer/icons/easyPlay.svg,sha256=4A39UEthvN6Jv0p75nxxKiVpqECRSweD89nbULLb49A,5591
13
+ easyplayer/icons/film-clapper.png,sha256=xWNdhWAITXLhDqZx8lfVYbvl6smBFMAyxPaTi_2bHM0,41422
14
+ easyplayer/icons/fullscreen.png,sha256=0x4UuVcdHZH_yt_6IRdsfFmHkxMycUoPNjOH0zyajCU,4322
15
+ easyplayer/icons/go-next.png,sha256=_tF0KYzI1up_Nqc0kxEcyqqjcmyfUvBP7Q02qqAGfv8,10365
16
+ easyplayer/icons/icomap.json,sha256=OM2x7yPr5qmDd_odW8HZAtRv5oOqTG4VPCfYxqHdMjE,3016
17
+ easyplayer/icons/info.png,sha256=H6RI8Yer2gnRyp5VR2nFlFj8zISUACoHgerndabAkmE,10917
18
+ easyplayer/icons/langflags.png,sha256=ogOEA3KPplleix0I9UFlHsJKGiu6kb99A8ovocsasSA,58832
19
+ easyplayer/icons/license.txt,sha256=nLwFv-RmmyZl4fVibZjXEHoVhNxHglrC1kqsjkGLg78,194
20
+ easyplayer/icons/loadfile.png,sha256=7YEo8GYcVbsVWDgEFQopKTvpPRnUxv-KqseltTmpgak,11772
21
+ easyplayer/icons/movie-icon.png,sha256=rNTDLL1T7xguEhthIJKXkehFNWjhqxnY-0PrtGJZRp8,12768
22
+ easyplayer/icons/newList.png,sha256=DiGuyLv8o81E3qNUkEOlErG_de-QiHPl_Tzqzagq4fw,9476
23
+ easyplayer/icons/next.png,sha256=3gvtgCgoRRH1UwEHog2L5acLDdvjTcdrdR1cTZJcmAA,7113
24
+ easyplayer/icons/pause.png,sha256=NPz85YvCErMUs1QOSCZ9KopYPkEgFfP4y1TLeErP7NI,9283
25
+ easyplayer/icons/play.png,sha256=aJg2k93liu4g7cE9HF6SdEwiaQ2oJusM_Zer2LK8F0A,10348
26
+ easyplayer/icons/previous.png,sha256=uFJY_7qZiVU-5rFzzT4X_y9kciSVupgTagErmccJMw4,7040
27
+ easyplayer/icons/save-as-icon.png,sha256=1_jFiIO0kSCQefL8CpIYl3wowe1T6ue842EUwLZAgqU,19625
28
+ easyplayer/icons/screenshot.png,sha256=C2g5kGcB1i0-nzUP6LalvM4BV9Ez2CUVvb0d--hmRrU,12315
29
+ easyplayer/icons/settings.png,sha256=2JPUeCiJ7ZQWK5eU7dlqDBJD2yOfpxo4zcywN2rR61U,25073
30
+ easyplayer/icons/speaker-high.png,sha256=ZSDk3ePsEnHeqiClenksw1eDofku4b5SgwysgGtbxr0,5358
31
+ easyplayer/icons/speaker-muted.png,sha256=uPBT1JVU_0HdVCkCLjScIoYP9gke-b_nMsVdBFoSRBc,5217
32
+ easyplayer/icons/splitVertical.png,sha256=M-OusZLoQ2d-hM5tVhKUBN2GCxyHMuKzcckbEhqtHBg,16122
33
+ easyplayer/icons/start-icon.png,sha256=iKPCXPkQfU1snvg7tdJWjoVrJYDo7cURnL7MIuSLM2s,5687
34
+ easyplayer/icons/stop-red-icon.png,sha256=IsYqbgPs4ikrlTS8iiKj2Nq7RiT0-Fq8wM_rBJsXoJs,3203
35
+ easyplayer/icons/video_clapper.png,sha256=GCimowGev2zMpnmmV7a9NpiiL0JQGtdM6qHy4aEhAaA,56090
36
+ easyplayer/icons/window-close.png,sha256=GK5Mok9px2hyKFcyVdcjidPdLdfE99s8ht2iALg78lU,15444
37
+ easyplayer/icons/flatdark/fullscreen.png,sha256=HlGcbtFK6IZQhcIE_S8fYLFmmkZvS8FZ-NL9jvi0yG0,14760
38
+ easyplayer/icons/flatdark/goto.svg,sha256=-RzidC47NUn1tTr6W2ltPjM0AjFEx5D3BT8F3J_k4aw,1939
39
+ easyplayer/icons/flatdark/info.svg,sha256=sYj79PHj5xrbSvonCY4nDXuiVkRGmh4tlo7avesevuo,2289
40
+ easyplayer/icons/flatdark/mute.svg,sha256=FVKraZ9Jr69UjLOClFj8Qh4UcSpvxaW01ok2K3Dva7Y,2424
41
+ easyplayer/icons/flatdark/newList.svg,sha256=Mev6b227hxIW4MSeGkVUEOfGGOggY0YwhDqO0qlXeBs,3342
42
+ easyplayer/icons/flatdark/open.svg,sha256=pjHp4A2QYsv0xDZ5GA6oKQbNAcqY9DTSPxmxUdIn13Q,1620
43
+ easyplayer/icons/flatdark/pause.svg,sha256=XWF9A3DBVMMjklnSzB1ZwIBqBUkjYnDF5h-Dc8n44jo,1306
44
+ easyplayer/icons/flatdark/play.svg,sha256=zALoG-g1gHFAphVMkovtZieTjyvFpvD9A2i5oLX703k,1535
45
+ easyplayer/icons/flatdark/remove.svg,sha256=rDMTpPshftckhl2exZkkp9yAmCCXThTaf9lVxUm1PZg,1425
46
+ easyplayer/icons/flatdark/remove_all.svg,sha256=izKMdJr7z2cZRzov9318B-m9OOa_zLMWZy9YV3zS5tU,2306
47
+ easyplayer/icons/flatdark/save.svg,sha256=Xn1z0oB__qePYJI1znlEkJj2rEwq9FilSyfFcBQtDcg,2006
48
+ easyplayer/icons/flatdark/screenshot.svg,sha256=2n7WATAwFHU3blWhwoNgEeXEQmMvuUoBtHvk5XNjOtQ,1712
49
+ easyplayer/icons/flatdark/settings.svg,sha256=3qI8zGwJTk0WmknoYol4ETWoMZTIuCDzNRrG0dD2J68,2325
50
+ easyplayer/icons/flatdark/sound.svg,sha256=nbkLDEyP8OWhKsBh1JVnLBY4yKnNHlIQkUJzVFANukM,2147
51
+ easyplayer/icons/flatdark/splitVertical.svg,sha256=-kaI9gOkjYvRNKX0mxRBRdvNKtvgDvsJlO8cuHkBLDs,201
52
+ easyplayer/icons/flatdark/start-cut.svg,sha256=ie7tyS1kPcY4mLMUi5T3Ir-SDvGx7h-CAH63bRCRyZE,1699
53
+ easyplayer/icons/flatdark/stop-cut.svg,sha256=9s0e092Ze-rrFZYZozG5_X52CrR7PHUpQJTloMenbDA,1743
54
+ easyplayer/icons/flaticons/fullscreen.png,sha256=nlRf-QPG4llrEkk27FjQE3vjlI5wE07sTGjZCGzSG5I,4894
55
+ easyplayer/icons/flaticons/goto.svg,sha256=0XpDsby0LbJAn1F1ILABrzQO6UDYukZX4fwAMD-gohM,744
56
+ easyplayer/icons/flaticons/info.svg,sha256=XUr9l0X1qaK61PqDkSytc5TL3GoWmz82v4UJXxkwhig,516
57
+ easyplayer/icons/flaticons/mute.svg,sha256=6PpJfTd9oLHE41HYzMW0zJEJzgBnIyuWQll2RSR3Uvw,1173
58
+ easyplayer/icons/flaticons/newList.svg,sha256=IrL6KVUg4Tu9uDBY1aI9wnswG5m19msU2Tshq3LQrlU,2042
59
+ easyplayer/icons/flaticons/open.svg,sha256=wFDiNrdxrZVlxDejs8S4dEGzTh0AdzXLzawzMhusQnw,489
60
+ easyplayer/icons/flaticons/pause.svg,sha256=SIY9O3JoO5y3Dkmaj2teBEGigxpL9QlZ7U7O4SXVPBo,284
61
+ easyplayer/icons/flaticons/play.svg,sha256=ZaXvt3jzhdNolPgIn7435aarxN5Ia1ce3ffnGeA76ls,1436
62
+ easyplayer/icons/flaticons/remove.svg,sha256=JN9-AZKB0y1xBrcGaLJJdQhGOYNVEFJuzBvcKG9qRfM,392
63
+ easyplayer/icons/flaticons/remove_all.svg,sha256=N_lPesbUB3rdXqyOLzO3ME6CdHsjK8lzWx9sZ6HdpFc,914
64
+ easyplayer/icons/flaticons/save.svg,sha256=E_R_tTY7xHB_qjxZmSC4VKlkR6xNeIg_NRMFXfBLCZ4,568
65
+ easyplayer/icons/flaticons/screenshot.svg,sha256=ATe0zu_TQU-AGfQdK3lSRjBHNIbKxEuS9bs4zD0wtMA,665
66
+ easyplayer/icons/flaticons/settings.svg,sha256=BTUgJIvi7IfU66wyrKFHqOqgLN9U2qcIIr4rOR8YpU0,1295
67
+ easyplayer/icons/flaticons/sound.svg,sha256=ZhNuqhhNjDSS-LIbt7yz0omYLrLkvskMvTsrQsDHLnU,933
68
+ easyplayer/icons/flaticons/splitVertical.svg,sha256=MWg9Ct8qjfTet8xOF35EdD2-TK4kZ8WSodgzFn3ohoI,185
69
+ easyplayer/icons/flaticons/start-cut.svg,sha256=ie7tyS1kPcY4mLMUi5T3Ir-SDvGx7h-CAH63bRCRyZE,1699
70
+ easyplayer/icons/flaticons/stop-cut.svg,sha256=9s0e092Ze-rrFZYZozG5_X52CrR7PHUpQJTloMenbDA,1743
71
+ easyplayer/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
72
+ easyplayer/lib/mpv.py,sha256=wFtV_MqGWUhugBsytwAI1HIZ_6gxgaNdsmh24Y-Jzk8,92910
73
+ easympv-1.4.0.dist-info/METADATA,sha256=8EBnSGLzh2T7iuEPUNZWKwLA1OUxsglwJD8E-lXTvSQ,5208
74
+ easympv-1.4.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
75
+ easympv-1.4.0.dist-info/entry_points.txt,sha256=tPTwnbnXIayz9RFCwJEB_uMvaSS0TGEloi1EG8eFtpk,58
76
+ easympv-1.4.0.dist-info/top_level.txt,sha256=YjFIl5m-ptoifGAMVIDXX1XpNQtYfGZf4EpsiPhBWto,11
77
+ easympv-1.4.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ easyplayer = easyplayer.EasyPlayer:main
@@ -0,0 +1 @@
1
+ easyplayer
@@ -0,0 +1,210 @@
1
+ import subprocess
2
+ from threading import Thread
3
+ from PyQt6 import QtWidgets, QtCore, QtGui
4
+ import FFMPEGTools
5
+
6
+ Log = FFMPEGTools.Log
7
+
8
+ try:
9
+ import numpy as np
10
+ HAS_SPECTRUM = True
11
+ except ImportError:
12
+ HAS_SPECTRUM = False
13
+
14
+ SPECTRUM_SAMPLE_RATE = 44100
15
+ SPECTRUM_BLOCK_SIZE = 4096
16
+
17
+
18
+ class ParecStream:
19
+ def __init__(self, device, samplerate, blocksize, callback):
20
+ self._proc = subprocess.Popen(
21
+ ['parec', f'--device={device}', '--format=float32le',
22
+ '--channels=1', f'--rate={samplerate}', '--latency-msec=20'],
23
+ stdout=subprocess.PIPE, stderr=subprocess.DEVNULL
24
+ )
25
+ self._blocksize = blocksize
26
+ self._callback = callback
27
+ self._stopped = False
28
+ self._thread = Thread(target=self._loop, daemon=True)
29
+
30
+ def start(self):
31
+ self._thread.start()
32
+
33
+ def stop(self):
34
+ self._stopped = True
35
+ self._proc.terminate()
36
+
37
+ def close(self):
38
+ try:
39
+ self._proc.wait(timeout=1)
40
+ except Exception:
41
+ pass
42
+ self._thread.join(timeout=1)
43
+
44
+ def _loop(self):
45
+ bytes_per_block = self._blocksize * 4
46
+ while not self._stopped:
47
+ data = self._proc.stdout.read(bytes_per_block)
48
+ if not data or len(data) < bytes_per_block:
49
+ break
50
+ if not self._stopped:
51
+ arr = np.frombuffer(data, dtype='float32').reshape(-1, 1)
52
+ self._callback(arr, self._blocksize, None, None)
53
+
54
+
55
+ class SpectrumOverlay(QtWidgets.QWidget):
56
+ BAND_EDGES = [50, 100, 200, 400, 800, 1600, 3200, 6400, 12800, 14000, 14500, 15000, 16000]
57
+ BANDS = len(BAND_EDGES) - 1
58
+ BAR_COLORS = ["heat", "rainbow", "blue", "green", "magenta", "red"]
59
+
60
+ def __init__(self, parent):
61
+ super().__init__(parent)
62
+ self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TransparentForMouseEvents, True)
63
+ from threading import Lock
64
+ self._mags = [0.0] * self.BANDS
65
+ self._lock = Lock()
66
+ self.mode = "heat"
67
+
68
+ def setMags(self, mags):
69
+ with self._lock:
70
+ self._mags = mags[:]
71
+ self.update()
72
+
73
+ def clearMags(self):
74
+ with self._lock:
75
+ self._mags = [0.0] * self.BANDS
76
+ self.update()
77
+
78
+ def paintEvent(self, __event):
79
+ with self._lock:
80
+ mags = self._mags[:]
81
+ mode = self.mode
82
+ painter = QtGui.QPainter(self)
83
+ painter.fillRect(self.rect(), QtGui.QColor(15, 15, 15))
84
+ w, h = self.width(), self.height()
85
+ bar_w = w // self.BANDS
86
+ gap = max(2, bar_w // 8)
87
+ for i, level in enumerate(mags):
88
+ bar_h = max(2, int(level * 0.9 * (h - 4)))
89
+ x = i * bar_w + gap
90
+ y = h - bar_h - 2
91
+ if mode == "red":
92
+ r = min(255, int(level * 2 * 255))
93
+ g = min(255, int((1.0 - level) * 2 * 255))
94
+ b = 0
95
+ color = QtGui.QColor(r, g, b)
96
+ elif mode == "magenta":
97
+ r = min(255, int(level * 2 * 255))
98
+ g = min(255, int((1.0 - level) * 2 * 255))
99
+ b = min(255, max(0, int((level * 2 - 1) * 255)))
100
+ color = QtGui.QColor(r, g, b)
101
+ elif mode == "blue":
102
+ r = 0
103
+ g = min(255, int((1.0 - level) * 2 * 255))
104
+ b = min(255, int(level * 2 * 255))
105
+ color = QtGui.QColor(r, g, b)
106
+ elif mode == "rainbow":
107
+ hue = int(i / SpectrumOverlay.BANDS * 300)
108
+ color = QtGui.QColor.fromHsv(hue, 220, max(30, int(level * 255)))
109
+ elif mode == "heat":
110
+ hue = int((1.0 - level) * 240)
111
+ color = QtGui.QColor.fromHsv(hue, 255, max(80, int(level * 255)))
112
+ else: # green
113
+ r = int((1.0 - level) * 255)
114
+ g = int((1.0 - level * 0.6) * 255)
115
+ b = 0
116
+ color = QtGui.QColor(r, g, b)
117
+ painter.fillRect(x, y, bar_w - gap * 2, bar_h, color)
118
+ painter.end()
119
+
120
+
121
+ class SpectrumController(QtCore.QObject):
122
+ def __init__(self, player):
123
+ super().__init__()
124
+ self._player = player
125
+ self._specStream = None
126
+ self._overlay = SpectrumOverlay(player)
127
+ self._overlay.hide()
128
+
129
+ @property
130
+ def overlay(self):
131
+ return self._overlay
132
+
133
+ def setGeometry(self, x, y, w, h):
134
+ self._overlay.setGeometry(x, y, w, h)
135
+
136
+ def setMode(self, mode):
137
+ self._overlay.mode = mode
138
+
139
+ def getMode(self):
140
+ return self._overlay.mode
141
+
142
+ def startCapture(self):
143
+ if not HAS_SPECTRUM or self._specStream is not None:
144
+ return
145
+ try:
146
+ device = self._findMonitorDevice()
147
+ if not device:
148
+ Log.warning("Spectrum capture failed - no monitor device found")
149
+ return
150
+ self._specStream = ParecStream(
151
+ device,
152
+ SPECTRUM_SAMPLE_RATE,
153
+ SPECTRUM_BLOCK_SIZE,
154
+ self._audioCallback
155
+ )
156
+ self._specStream.start()
157
+ self._overlay.show()
158
+ except Exception:
159
+ Log.warning("Spectrum capture failed - no valid device found")
160
+
161
+ def stopCapture(self):
162
+ if self._specStream:
163
+ try:
164
+ self._specStream.stop()
165
+ self._specStream.close()
166
+ except Exception:
167
+ pass
168
+ self._specStream = None
169
+ self._overlay.hide()
170
+ self._overlay.clearMags()
171
+
172
+ def _findMonitorDevice(self):
173
+ try:
174
+ result = subprocess.run(['pactl', 'get-default-sink'], capture_output=True, text=True, timeout=2)
175
+ if result.returncode == 0:
176
+ monitor = result.stdout.strip() + '.monitor'
177
+ Log.info("Spectrum: using parec with monitor source %s", monitor)
178
+ return monitor
179
+ except Exception:
180
+ pass
181
+ Log.info("Spectrum: no monitor device found")
182
+ return None
183
+
184
+ def _audioCallback(self, indata, __frames, __time, __status):
185
+ data = indata[:, 0]
186
+ windowed = data * np.hanning(len(data))
187
+ fft_data = np.abs(np.fft.rfft(windowed))
188
+ freqs = np.fft.rfftfreq(len(data), 1.0 / SPECTRUM_SAMPLE_RATE)
189
+ DB_FLOOR = -100.0
190
+ reference = SPECTRUM_BLOCK_SIZE / 15.0
191
+ new_mags = []
192
+ for i in range(SpectrumOverlay.BANDS):
193
+ mask = (freqs >= SpectrumOverlay.BAND_EDGES[i]) & (freqs < SpectrumOverlay.BAND_EDGES[i + 1])
194
+ if mask.any():
195
+ val = float(np.max(fft_data[mask])) / reference
196
+ db = 20.0 * np.log10(val) if val > 0 else DB_FLOOR
197
+ if i >= SpectrumOverlay.BANDS - 4:
198
+ db += 6.0
199
+ new_mags.append(max(0.0, min(1.0, (db - DB_FLOOR) / -DB_FLOOR)))
200
+ else:
201
+ new_mags.append(0.0)
202
+ with self._overlay._lock:
203
+ riseFactor = 0.5
204
+ decayFactor = 0.9
205
+ for i in range(SpectrumOverlay.BANDS):
206
+ if new_mags[i] > self._overlay._mags[i]:
207
+ self._overlay._mags[i] += riseFactor * (new_mags[i] - self._overlay._mags[i])
208
+ else:
209
+ self._overlay._mags[i] *= decayFactor
210
+ self._overlay.update()