Esempio n. 1
0
 def _setupLyrics(self):
     self._logger.info(">> Setting up lyrics...")
     if self._player.getCurrentMusic().isAbsent():
         self._logger.info("No music, return")
         return
     currentMusic = self._player.getCurrentMusic().orElseThrow(AssertionError)
     lyricsPath = Path(currentMusic.filename).with_suffix(".lrc")
     lyricsText = lyricsPath.read_text(encoding="gbk")
     self._logger.info("Parsing lyrics")
     lyrics = LyricUtils.parseLyrics(lyricsText)
     self._logger.info("Lyrics count: %d", len(lyrics))
     self._lyrics = lyrics
     self._prevLyricIndex = -1
     LayoutUtils.clearLayout(self._layout)
     self._layout.addSpacing(self.height() // 2)
     for position, lyric in list(lyrics.items())[:]:
         lyricLabel = ClickableLabel(lyric, self)
         lyricLabel.setAlignment(
             gg(QtCore.Qt.AlignmentFlag.AlignCenter, Any) | QtCore.Qt.AlignmentFlag.AlignVCenter)
         lyricLabel.clicked.connect(
             lambda _, position=position: self._player.setPosition(position))
         lyricLabel.setMargin(int(2 * self._app.getZoom()))
         self._layout.addWidget(lyricLabel)
     self._layout.addSpacing(self.height() // 2)
     self._logger.info("Lyrics layout has children: %d", self._layout.count())
     self.verticalScrollBar().setValue(0)
     self._logger.info("<< Lyrics set up")
Esempio n. 2
0
 def findPluginClassesInFolder(self, folder):
     self._logger.info("Find plugin classes in folder: %s", folder)
     from IceSpringMusicPlayer.common.pluginMixin import PluginMixin
     classes = set()
     pluginRoot = Path("IceSpringMusicPlayer/plugins")
     for path in Path(folder).glob("**/*.py"):
         package = ".".join([
             x for x in path.relative_to(pluginRoot).parts
             if x != "__init__.py"
         ]).rstrip(".py")
         for x in importlib.import_module(package).__dict__.values():
             if isinstance(x, type) and issubclass(
                     x, PluginMixin) and x != PluginMixin:
                 classes.add(x)
     return sorted(classes, key=lambda x: x.__module__ + "." + x.__name__)
Esempio n. 3
0
def run() -> None:
    from IceSpringMusicPlayer.utils.logUtils import LogUtils
    from IceSpringMusicPlayer.utils.pydubUtils import PydubUtils
    LogUtils.initLogging()
    PydubUtils.patchPydub()
    sys.path.append(str(Path(__file__).parent / "plugins"))
    from IceSpringMusicPlayer.app import App
    App().exec_()
Esempio n. 4
0
 def addMusicsFromFileDialog(self):
     self._logger.info("Add musics from file dialog")
     musicRoot = str(Path("~/Music").expanduser().absolute())
     filenames = QtWidgets.QFileDialog.getOpenFileNames(
         None, "Open music files", musicRoot,
         "Audio files (*.mp3 *.wma) ;; All files (*)")[0]
     self._logger.info("There are %d files to open", len(filenames))
     self.addMusicsFromFilenames(filenames)
Esempio n. 5
0
 def _loadConfig(self) -> Config:
     self._logger.info("Load config")
     path = Path("config.json")
     if not path.exists():
         self._logger.info("No config.json file, return default config")
         return self.getDefaultConfig()
     jd = json.loads(path.read_text(), object_pairs_hook=Config.fromJson)
     config = Config(
         **{
             **self.getDefaultConfig().__dict__,
             **{k: v
                for k, v in jd.items() if k in Config.__annotations__}
         })
     self._logger.info("Process plugin configs (%d plugins)",
                       len(self._pluginService.getPluginClasses()))
     for plugin in config.plugins:
         self._logger.info("Plugin in config: %s", plugin)
         jd = json.loads(json.dumps(
             plugin.config,
             default=plugin.clazz.getPluginConfigClass().pythonToJson),
                         object_pairs_hook=plugin.clazz.
                         getPluginConfigClass().jsonToPython)
         plugin.config = gg(plugin.clazz.getPluginConfigClass())(**jd)
     self._logger.info("Process plugins not in config")
     loadedClasses = [x.clazz for x in config.plugins]
     for clazz in self._pluginService.getPluginClasses():
         if clazz not in loadedClasses:
             self._logger.info("Plugin not in config: %s", clazz)
             config.plugins.append(
                 Plugin(clazz=clazz,
                        disabled=False,
                        config=clazz.getPluginConfigClass().
                        getDefaultObject()))
     self._logger.info("Sort plugins")
     config.plugins.sort(
         key=lambda x: x.clazz.__module__ + "." + x.clazz.__name__)
     self._logger.info("Load layout config")
     self._loadElementConfig(config.layout)
     self._logger.info("Loaded config: %s", config)
     return config
Esempio n. 6
0
 def persistConfig(self):
     self._logger.info("Persist, refresh current config")
     self._config.layout = self._app.getMainWindow().calcLayout()
     self._config.volume = self._app.getPlayer().getVolume()
     self._config.playbackMode = self._app.getPlayer().getPlaybackMode()
     self._config.frontPlaylistIndex = self._app.getPlayer(
     ).getFrontPlaylistIndex()
     self._logger.info("Save to config.json")
     Path("config.json").write_text(
         json.dumps(self._config,
                    indent=4,
                    ensure_ascii=False,
                    default=Config.toJson))
Esempio n. 7
0
 def loadTestData(self):
     self._logger.info("Load test data")
     paths = Path("~/Music").expanduser().glob("**/*.mp3")
     musics = [MusicUtils.parseMusic(str(x)) for x in paths]
     self._player.setFrontPlaylistIndex(self._player.insertPlaylist())
     self._player.insertMusics(
         [x for i, x in enumerate(musics) if i % 6 in (0, 1, 2)])
     self._player.setFrontPlaylistIndex(self._player.insertPlaylist())
     self._player.insertMusics(
         [x for i, x in enumerate(musics) if i % 6 in (3, 4)])
     self._player.setFrontPlaylistIndex(self._player.insertPlaylist())
     self._player.insertMusics(
         [x for i, x in enumerate(musics) if i % 6 in (5, )])
 def setMedia(self,
              media: QtMultimedia.QMediaContent,
              stream: QtCore.QIODevice = None,
              realDuration=None) -> None:
     self.blockSignals(True)
     super().setMedia(media, stream)
     self.blockSignals(False)
     self._realDuration = realDuration
     self._lastFakePosition = 0
     self._bugRate = 0.0
     if realDuration is None:
         filename = media.canonicalUrl().toLocalFile()
         file = taglib.File(filename)
         bitrate = file.bitrate
         file.close()
         self._realDuration = Path(filename).stat().st_size * 8 // bitrate
Esempio n. 9
0
 def removePlugin(self, plugin: Plugin) -> None:
     self._logger.info("Remove plugin: %s", plugin.clazz)
     assert not plugin.clazz.isSystemPlugin()
     assert not self.isPluginUsedInMainWindow(
         plugin), "Plugin used in main window"
     stem = plugin.clazz.__module__.split(".")[0]
     path = Path(f"IceSpringMusicPlayer/plugins/{stem}")
     self._logger.info("Remove plugin folder: %s", path)
     now = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
     targetPath = Path(f"IceSpringMusicPlayer/recycles/{now}/{stem}")
     self._logger.info("Plugin is backup to %s", targetPath)
     targetPath.parent.mkdir(parents=True, exist_ok=True)
     path.copytree(targetPath)
     path.rmtree()
     self._logger.info("Remove plugin from registry")
     self._app.getConfig().plugins.remove(plugin)
     self._logger.info("> Signal pluginRemoved emitting...")
     self.pluginsRemoved.emit([plugin])
     self._logger.info("< Signal pluginRemoved emitted.")
Esempio n. 10
0
 def addMusicsFromFolder(self, folder: str) -> None:
     self._logger.info("Add musics from folder: %s", folder)
     paths = Path(folder).expanduser().glob("**/*.mp3")
     filenames = [str(x) for x in paths]
     self.addMusicsFromFilenames(filenames)
Esempio n. 11
0
import importlib.util
import logging
import os
import re
import shutil
import sys
from subprocess import Popen, PIPE

import PyInstaller.__main__
from IceSpringPathLib import Path
from PyInstaller.utils.hooks import collect_submodules

from IceSpringMusicPlayer.utils.logUtils import LogUtils

name = "IceSpringMusicPlayer"
vsHome = Path(r"C:\Program Files (x86)\Microsoft Visual Studio\2019").absolute()
vcvarsall = vsHome / r"BuildTools\VC\Auxiliary\Build\vcvarsall.bat"
ffmpegHome = Path("./ffmpeg").absolute()
fftwDll = Path("libfftw3f-3.dll").absolute()
assert vsHome.exists()
assert vcvarsall.exists()
assert ffmpegHome.exists()
assert ffmpegHome.__truediv__("ffmpeg.exe").exists()
assert ffmpegHome.__truediv__("ffprobe.exe").exists()
assert fftwDll.exists()

LogUtils.initLogging()
logging.getLogger().setLevel(logging.INFO)
logging.info("Removing application directory if exists...")
Path(f"dist/{name}").exists() and Path(f"dist/{name}").rmtree()
Esempio n. 12
0
 def _verifyPluginFolder(
         self, folder: str) -> typing.List[typing.Type[PluginMixin]]:
     self._logger.info("Verify plugin in folder: %s", folder)
     oldClasses = [x.clazz for x in self._app.getConfig().plugins]
     root = Path(folder)
     if not (root / "__init__.py").exists():
         raise RuntimeError("Plugin folder must contains __init__.py")
     targetPath = Path(f"IceSpringMusicPlayer/plugins/{root.name}")
     if targetPath.exists():
         self._logger.info("Plugin already exists.")
         raise RuntimeError("Plugin Already Exists")
     self._logger.info("Copy plugin folder to plugins dir %s", targetPath)
     root.copytree(targetPath)
     try:
         classes = self.findPluginClassesInFolder(str(targetPath))
         classes = [x for x in classes if x not in oldClasses]
     except Exception as e:
         self._logger.info("Exception occurred: %s", e, e)
         self._logger.info("Remove folder: %s", targetPath)
         targetPath.rmtree()
         raise e
     if len(classes) == 0:
         self._logger.info("No plugin found in folder, remove folder")
         targetPath.rmtree()
         raise RuntimeError("No plugin found")
     return classes