def QImage_to_compressed_bytes(qimage, format):
    """
    Compress QImage or QPixmap into bytes corresponding to a image file format (BMP,PNG,JPG)

    To reconstruct the QImage or QPixamp :
    image = QImage.fromData(data)
    image = QImage() ; image.loadFromData(data)
    image = QPixmap(); image.loadFromData(data)


    The QImage.format will be preserved when loading only if in format in :
    Format_Mono
    Format_Indexed8
    Format_RGB32
    Format_ARGB32
    Format_Grayscale8

    """
    # https://stackoverflow.com/questions/24965646/convert-pyqt4-qtgui-qimage-object-to-base64-png-data
    # https://stackoverflow.com/questions/57404778/how-to-convert-a-qpixmaps-image-into-a-bytes

    qbytearray = QByteArray()
    qbuffer = QBuffer(qbytearray)
    qbuffer.open(QIODevice.WriteOnly)
    ok = qimage.save(qbuffer, format)
    assert ok
    return qbytearray.data()  # fait une copie ?
예제 #2
0
def export_to_clipboard_as_svg(scene):
    print(f"exporting SVG to clipboard")
    buffer = QBuffer()
    svg_gen = QSvgGenerator()
    svg_gen.setOutputDevice(buffer)
    render_to_svggen(scene, svg_gen)
    data = QMimeData()
    data.setData("image/svg+xml", buffer.buffer())
    qApp.clipboard().setMimeData(data, QClipboard.Clipboard)
예제 #3
0
 def base64_from_icon_obj(self, icon_obj, width, height):
     """Convert icon object to base64 encoding."""
     image = QImage(icon_obj.pixmap(width, height).toImage())
     byte_array = QByteArray()
     buffer = QBuffer(byte_array)
     image.save(buffer, "PNG")
     return byte_array.toBase64().data().decode()
예제 #4
0
 def save(self, fname, format, draft):
     if is_text_string(fname):
         if format == "pdf":
             self.app = guidata.qapplication()
             if draft:
                 mode = QPrinter.ScreenResolution
             else:
                 mode = QPrinter.HighResolution
             printer = QPrinter(mode)
             printer.setOutputFormat(QPrinter.PdfFormat)
             printer.setOrientation(QPrinter.Landscape)
             printer.setOutputFileName(fname)
             printer.setCreator("guiqwt.pyplot")
             self.print_(printer)
         else:
             if self.win is None:
                 self.show()
             if PYQT5:
                 pixmap = self.win.centralWidget().grab()
             else:
                 pixmap = QPixmap.grabWidget(self.win.centralWidget())
             pixmap.save(fname, format.upper())
     else:
         # Buffer
         fd = fname
         assert hasattr(fd, "write"), "object is not file-like as expected"
         if self.win is None:
             self.show()
         pixmap = QPixmap.grabWidget(self.win.centralWidget())
         buff = QBuffer()
         buff.open(QIODevice.ReadWrite)
         pixmap.save(buff, format.upper())
         fd.write(buff.data())
         buff.close()
         fd.seek(0)
예제 #5
0
파일: utils.py 프로젝트: CEMES-CNRS/PyMoDAQ
def pngbinary2Qlabel(databinary):
    buff = QBuffer()
    buff.open(QIODevice.WriteOnly)
    buff.write(databinary)
    dat = buff.data()
    pixmap = QtGui.QPixmap()
    pixmap.loadFromData(dat, 'PNG')
    label = QtWidgets.QLabel()
    label.setPixmap(pixmap)
    return label
예제 #6
0
def qt_to_pil_image(qimg):
    buffer = QBuffer()
    buffer.open(QIODevice.ReadWrite)
    # preserve alha channel with png
    # otherwise ppm is more friendly with Image.open
    if qimg.hasAlphaChannel():
        qimg.save(buffer, 'png')
    else:
        qimg.save(buffer, 'ppm')

    b = BytesIO()
    try:
        b.write(buffer.data())
    except TypeError:
        # the types seemed to change between versions of qtpy
        b.write(buffer.data().data())
    buffer.close()
    b.seek(0)

    pil_img = Image.open(b)
    return pil_img
예제 #7
0
    def _download(
        self,
        url,
        path=None,
        force=False,
        verify=True,
        chunked=True,
    ):
        """Callback for download."""
        if path is None:
            path = url.split('/')[-1]

        # Make dir if non existent
        folder = os.path.dirname(os.path.abspath(path))

        if not os.path.isdir(folder):
            os.makedirs(folder)

        # Get headers
        try:
            r = requests.head(
                url,
                proxies=self.proxy_servers,
                verify=verify,
                timeout=self.DEFAULT_TIMEOUT,
            )
            status_code = r.status_code
        except Exception as error:
            status_code = -1
            logger.error(str(error))

        logger.debug('Status code {0} - url'.format(status_code, url))

        if status_code != 200:
            logger.error('Invalid url {0}'.format(url))
            return path

        total_size = int(r.headers.get('Content-Length', 0))

        # Check if file exists
        if os.path.isfile(path) and not force:
            file_size = os.path.getsize(path)
        else:
            file_size = -1

        # print(path, total_size, file_size)

        # Check if existing file matches size of requested file
        if file_size == total_size:
            self._sig_download_finished.emit(url, path)
            return path
        else:
            try:
                r = requests.get(
                    url,
                    stream=chunked,
                    proxies=self.proxy_servers,
                    verify=verify,
                    timeout=self.DEFAULT_TIMEOUT,
                )
                status_code = r.status_code
            except Exception as error:
                status_code = -1
                logger.error(str(error))

        # File not found or file size did not match. Download file.
        progress_size = 0
        bytes_stream = QBuffer()  # BytesIO was segfaulting for big files
        bytes_stream.open(QBuffer.ReadWrite)

        # For some chunked content the app segfaults (with big files)
        # so now chunked is a kwarg for this method
        if chunked:
            for chunk in r.iter_content(chunk_size=self._chunk_size):
                # print(url, progress_size, total_size)
                if chunk:
                    bytes_stream.write(chunk)
                    progress_size += len(chunk)
                    self._sig_download_progress.emit(
                        url,
                        path,
                        progress_size,
                        total_size,
                    )
        else:
            bytes_stream.write(r.content)

        bytes_stream.seek(0)
        data = bytes_stream.data()

        with open(path, 'wb') as f:
            f.write(data)

        bytes_stream.close()

        self._sig_download_finished.emit(url, path)

        return path
예제 #8
0
    def __init__(self):
        super().__init__()

        self.setWindowTitle("OkPlayer")

        icon = QIcon()
        icon.addPixmap(QPixmap("ok_64x64.ico"), QIcon.Normal, QIcon.Off)
        self.setWindowIcon(icon)

        self.recent_file_acts = []
        self.init_menu()
        self.now = datetime.now()

        # Setting
        self.setting = {}
        self.load_setting()

        # Status bar
        self.learning_time_ms = 0
        self.learning_time_ms_total = self.setting.get(
            "learning_time_ms_total", 0)
        self.status_bar = self.statusBar()
        self.label_learning_time = QLabel(self)
        self.label_learning_time.setAlignment(Qt.AlignRight)

        self.status_bar.addPermanentWidget(self.label_learning_time)
        self.label_learning_time.setText(
            f"Learning time: 00:00"
            f" / total {ms2min_sec(self.learning_time_ms_total)}")

        # Timer for learning time
        self.timer_learning_time = QTimer(self)
        self.timer_learning_time.timeout.connect(self.update_learning_time)
        self.timer_learning_time.setInterval(1000)

        # Player
        self.player = QMediaPlayer(self)
        self.player.mediaStatusChanged.connect(self.qmp_status_changed)
        self.player.positionChanged.connect(self.qmp_position_changed)
        self.player.setNotifyInterval(50)
        self.player.setVolume(50)
        self.player_buf = QBuffer()
        self.path_media = ""
        self.music_data = None
        self.duration_ms = 0
        self.duration_str = ""

        # A/B Loop
        self.pos_loop_a = None
        self.pos_loop_b = None

        # Layout
        self.label_music = QLabel("No music", self)

        self.ico_play = qta.icon("fa.play")
        self.ico_pause = qta.icon("fa.pause")

        layout = QVBoxLayout()
        layout_volume = QHBoxLayout()
        layout_btn_progress = QVBoxLayout()
        layout_music_btns = QHBoxLayout()
        self.btn_rewind = QPushButton(qta.icon("fa.backward"), "", self)
        self.btn_rewind.clicked.connect(self.rewind)
        self.btn_play = QPushButton(self.ico_play, "", self)
        self.btn_play.clicked.connect(self.play)
        self.btn_fastforward = QPushButton(qta.icon("fa.forward"), "", self)
        self.btn_fastforward.clicked.connect(self.fastforward)

        self.btn_rewind.setFocusPolicy(Qt.NoFocus)
        self.btn_play.setFocusPolicy(Qt.NoFocus)
        self.btn_fastforward.setFocusPolicy(Qt.NoFocus)

        layout_music_btns.addWidget(self.btn_rewind)
        layout_music_btns.addWidget(self.btn_play)
        layout_music_btns.addWidget(self.btn_fastforward)

        layout_progress = QHBoxLayout()
        self.progressbar = MusicProgressBar(self)
        self.progressbar.sig_pb_pos.connect(self.set_media_position)
        self.elapsed_time = QLineEdit(f"00:00 / 00:00", self)
        self.elapsed_time.setReadOnly(True)
        self.elapsed_time.setAlignment(Qt.AlignHCenter)

        layout_progress.addWidget(self.progressbar)
        layout_progress.addWidget(self.elapsed_time)

        layout_btn_progress.addWidget(self.label_music)
        layout_btn_progress.addLayout(layout_music_btns)
        layout_btn_progress.addLayout(layout_progress)

        # Volume
        self.qdial_volume = QDial(self)
        self.qdial_volume.setMinimumWidth(110)
        self.qdial_volume.setWrapping(False)
        self.qdial_volume.setNotchesVisible(True)
        self.qdial_volume.setMinimum(0)
        self.qdial_volume.setMaximum(100)
        self.qdial_volume.setValue(self.player.volume())
        self.qdial_volume.valueChanged.connect(self.qdial_changed)

        layout_volume.addLayout(layout_btn_progress)
        layout_volume.addWidget(self.qdial_volume)

        # Lyrics
        self.display_lyrics = LyricsDisplay(self)
        layout.addLayout(layout_volume)
        layout.addWidget(self.display_lyrics)

        central_widget = QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

        # Auto Play
        self.update_recent_file_action()
        path = self.setting.get("LastPlayedPath", "")
        if osp.isfile(path):
            self.load_music_file(path)

        self.setFocus()
예제 #9
0
class MainWindow(QMainWindow):
    max_recent_files = 10

    def __init__(self):
        super().__init__()

        self.setWindowTitle("OkPlayer")

        icon = QIcon()
        icon.addPixmap(QPixmap("ok_64x64.ico"), QIcon.Normal, QIcon.Off)
        self.setWindowIcon(icon)

        self.recent_file_acts = []
        self.init_menu()
        self.now = datetime.now()

        # Setting
        self.setting = {}
        self.load_setting()

        # Status bar
        self.learning_time_ms = 0
        self.learning_time_ms_total = self.setting.get(
            "learning_time_ms_total", 0)
        self.status_bar = self.statusBar()
        self.label_learning_time = QLabel(self)
        self.label_learning_time.setAlignment(Qt.AlignRight)

        self.status_bar.addPermanentWidget(self.label_learning_time)
        self.label_learning_time.setText(
            f"Learning time: 00:00"
            f" / total {ms2min_sec(self.learning_time_ms_total)}")

        # Timer for learning time
        self.timer_learning_time = QTimer(self)
        self.timer_learning_time.timeout.connect(self.update_learning_time)
        self.timer_learning_time.setInterval(1000)

        # Player
        self.player = QMediaPlayer(self)
        self.player.mediaStatusChanged.connect(self.qmp_status_changed)
        self.player.positionChanged.connect(self.qmp_position_changed)
        self.player.setNotifyInterval(50)
        self.player.setVolume(50)
        self.player_buf = QBuffer()
        self.path_media = ""
        self.music_data = None
        self.duration_ms = 0
        self.duration_str = ""

        # A/B Loop
        self.pos_loop_a = None
        self.pos_loop_b = None

        # Layout
        self.label_music = QLabel("No music", self)

        self.ico_play = qta.icon("fa.play")
        self.ico_pause = qta.icon("fa.pause")

        layout = QVBoxLayout()
        layout_volume = QHBoxLayout()
        layout_btn_progress = QVBoxLayout()
        layout_music_btns = QHBoxLayout()
        self.btn_rewind = QPushButton(qta.icon("fa.backward"), "", self)
        self.btn_rewind.clicked.connect(self.rewind)
        self.btn_play = QPushButton(self.ico_play, "", self)
        self.btn_play.clicked.connect(self.play)
        self.btn_fastforward = QPushButton(qta.icon("fa.forward"), "", self)
        self.btn_fastforward.clicked.connect(self.fastforward)

        self.btn_rewind.setFocusPolicy(Qt.NoFocus)
        self.btn_play.setFocusPolicy(Qt.NoFocus)
        self.btn_fastforward.setFocusPolicy(Qt.NoFocus)

        layout_music_btns.addWidget(self.btn_rewind)
        layout_music_btns.addWidget(self.btn_play)
        layout_music_btns.addWidget(self.btn_fastforward)

        layout_progress = QHBoxLayout()
        self.progressbar = MusicProgressBar(self)
        self.progressbar.sig_pb_pos.connect(self.set_media_position)
        self.elapsed_time = QLineEdit(f"00:00 / 00:00", self)
        self.elapsed_time.setReadOnly(True)
        self.elapsed_time.setAlignment(Qt.AlignHCenter)

        layout_progress.addWidget(self.progressbar)
        layout_progress.addWidget(self.elapsed_time)

        layout_btn_progress.addWidget(self.label_music)
        layout_btn_progress.addLayout(layout_music_btns)
        layout_btn_progress.addLayout(layout_progress)

        # Volume
        self.qdial_volume = QDial(self)
        self.qdial_volume.setMinimumWidth(110)
        self.qdial_volume.setWrapping(False)
        self.qdial_volume.setNotchesVisible(True)
        self.qdial_volume.setMinimum(0)
        self.qdial_volume.setMaximum(100)
        self.qdial_volume.setValue(self.player.volume())
        self.qdial_volume.valueChanged.connect(self.qdial_changed)

        layout_volume.addLayout(layout_btn_progress)
        layout_volume.addWidget(self.qdial_volume)

        # Lyrics
        self.display_lyrics = LyricsDisplay(self)
        layout.addLayout(layout_volume)
        layout.addWidget(self.display_lyrics)

        central_widget = QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

        # Auto Play
        self.update_recent_file_action()
        path = self.setting.get("LastPlayedPath", "")
        if osp.isfile(path):
            self.load_music_file(path)

        self.setFocus()

    def init_menu(self):
        """Init menu."""
        color_icon = "#87939A"
        menu_bar = self.menuBar()
        menu_bar.setNativeMenuBar(False)  # Don't use mac native menu bar

        # File
        file_menu = menu_bar.addMenu("&File")

        # Open
        open_action = QAction(qta.icon("ei.folder-open", color=color_icon),
                              "&Open", self)
        open_action.setShortcut("Ctrl+O")
        open_action.setStatusTip("Open file")
        open_action.triggered.connect(self.open_music_file)
        file_menu.addAction(open_action)
        file_menu.addSeparator()

        # Recent Files
        for i in range(MainWindow.max_recent_files):
            self.recent_file_acts.append(
                QAction(self, visible=False, triggered=self.load_recent_music))
        for i in range(MainWindow.max_recent_files):
            file_menu.addAction(self.recent_file_acts[i])

        file_menu.addSeparator()

        # Exit
        exit_action = QAction(qta.icon("mdi.exit-run", color=color_icon),
                              "&Exit", self)
        exit_action.setShortcut("Ctrl+Q")
        exit_action.setStatusTip("Exit App")
        exit_action.triggered.connect(self.close)
        file_menu.addAction(exit_action)

        # Help
        help_menu = menu_bar.addMenu("&Help")
        about_action = QAction(
            "&About",
            self,
            statusTip="Show the application's About box",
            triggered=self.about,
        )
        help_menu.addAction(about_action)

    def about(self):
        """Show messagebox for about."""
        QMessageBox.about(
            self,
            "About music player a/b loop",
            "The music player a/b loop is made by <b>ok97465</b>",
        )

    def update_recent_file_action(self):
        """Update recent file action."""
        files = self.setting.get("recent_files", [])

        num_recent_files = min(len(files), MainWindow.max_recent_files)

        for i in range(num_recent_files):
            text = osp.splitext(osp.basename(files[i]))[0]
            self.recent_file_acts[i].setText(text)
            self.recent_file_acts[i].setData(files[i])
            self.recent_file_acts[i].setVisible(True)

        for j in range(num_recent_files, MainWindow.max_recent_files):
            self.recent_file_acts[j].setVisible(False)

    def open_music_file(self):
        """Open music file."""
        self.stop()
        fname = QFileDialog.getOpenFileName(
            self,
            "Open music file",
            "/home/ok97465",
            filter="Music Files (*.mp3, *.m4a)",
        )
        self.load_music_file(fname[0])

    def load_music_file(self, path: str):
        """Load music file"""
        if not osp.isfile(path):
            return
        self.path_media = path

        path_lyrics = path[:-3] + "vtt"
        self.display_lyrics.read_vtt(path_lyrics)

        fp = io.BytesIO()
        self.music_data = AudioSegment.from_file(path)
        self.music_data.export(fp, format="wav")
        self.player_buf.setData(fp.getvalue())
        self.player_buf.open(QIODevice.ReadOnly)
        self.player.setMedia(QMediaContent(), self.player_buf)

    def load_recent_music(self):
        """Load recent music."""
        action = self.sender()
        if action:
            self.stop()
            self.load_music_file(action.data())

    def load_setting(self):
        """Load setting file."""
        try:
            with open("setting.json", "r") as fp:
                self.setting = json.load(fp)
        except FileNotFoundError:
            pass

    def keyPressEvent(self, event):
        key = event.key()
        shift = event.modifiers() & Qt.ShiftModifier
        if shift:
            if key == Qt.Key_O:
                self.adjust_ab_loop(-100)
        else:
            if key in [Qt.Key_H, Qt.Key_Left, Qt.Key_A]:
                self.rewind(ms=5000)
            elif key in [Qt.Key_L, Qt.Key_Right, Qt.Key_D]:
                self.fastforward(ms=5000)
            elif key in [Qt.Key_J]:
                self.rewind(ms=1000 * 38)
            elif key in [Qt.Key_K, Qt.Key_F]:
                self.fastforward(ms=1000 * 38)
            elif key == Qt.Key_Up:
                self.control_volume(5)
            elif key == Qt.Key_Down:
                self.control_volume(-5)
            elif key in [Qt.Key_I, Qt.Key_W, Qt.Key_Menu]:
                self.set_ab_loop()
            elif key == Qt.Key_O:
                self.adjust_ab_loop(500)
            elif key in [Qt.Key_Space, Qt.Key_Hangul_Hanja]:
                self.play()
            elif key in [Qt.Key_S]:
                self.save_ab_loop()
            elif key in [Qt.Key_Q, Qt.Key_U, Qt.Key_Slash]:
                self.send_AB_loop_lyrics_to_papago()

        super().keyPressEvent(event)

    def set_ab_loop(self):
        """Set A/B loop."""
        if self.pos_loop_b:
            self.pos_loop_b = None
            self.pos_loop_a = None
        elif self.pos_loop_a:
            self.pos_loop_b = self.player.position()
            self.player.setPosition(self.pos_loop_a)
        else:
            self.pos_loop_a = self.player.position()

        self.progressbar.pos_loop_a = self.pos_loop_a
        self.progressbar.pos_loop_b = self.pos_loop_b
        self.progressbar.repaint()

    def adjust_ab_loop(self, offset_ms):
        """Adjust A/B loop."""
        if self.pos_loop_b:
            self.pos_loop_b += offset_ms
            self.pos_loop_a += offset_ms

    def save_ab_loop(self):
        """Save A/B loop"""
        if self.pos_loop_b is None:
            return

        is_playing = False
        if self.player.state() == QMediaPlayer.PlayingState:
            is_playing = True

        if is_playing:
            self.player.pause()
        path_new = (self.path_media[:-4] +
                    f"{self.pos_loop_a}_{self.pos_loop_b}" +
                    self.path_media[-4:])
        seg = self.music_data[self.pos_loop_a:self.pos_loop_b]
        seg.export(path_new, format="mp3")

        if is_playing:
            self.player.play()

    def play(self):
        """Play music file."""
        if self.player.state() == QMediaPlayer.PlayingState:
            self.player.pause()
            self.btn_play.setIcon(self.ico_play)
            self.timer_learning_time.stop()
        else:
            self.player.play()
            self.btn_play.setIcon(self.ico_pause)
            self.timer_learning_time.start()

    def stop(self):
        """Stop."""
        self.save_current_media_info()
        self.player.stop()
        self.player_buf.close()
        self.path_media = ""
        self.pos_loop_b = None
        self.pos_loop_a = None
        self.timer_learning_time.stop()
        self.label_music.setText("No music")
        self.btn_play.setIcon(self.ico_play)

    def control_volume(self, step: int):
        """Control volume."""
        volume = self.player.volume()
        if step < 0:
            new_volume = max([0, volume + step])
        else:
            new_volume = min([100, volume + step])
        self.qdial_volume.setValue(new_volume)

    def navigate_media(self, ms: int):
        """Navigate the position of media."""
        position_ms = self.player.position()
        if ms < 0:
            new_position_ms = max([0, position_ms + ms])
        else:
            new_position_ms = min([self.duration_ms, position_ms + ms])
        self.player.setPosition(new_position_ms)

    def rewind(self, ms: int = 5000):
        """Re-wind media of QMediaPlayer."""
        self.navigate_media(ms * -1)

    def fastforward(self, ms: int = 5000):
        """fastfoward media of QMediaPlayer."""
        self.navigate_media(ms)

    def qmp_status_changed(self):
        """Handle status of QMediaPlayer if the status is changed."""
        status = self.player.mediaStatus()
        if status == QMediaPlayer.LoadedMedia and self.path_media:
            duration_ms = self.player.duration()
            self.duration_ms = duration_ms
            self.duration_str = ms2min_sec(duration_ms)
            self.elapsed_time.setText(f"00:00 / {self.duration_str}")
            self.progressbar.setMaximum(duration_ms)
            music_basename = osp.splitext(osp.basename(self.path_media))[0]
            self.label_music.setText(music_basename)
            self.player.play()

            # read previous position
            path = self.path_media
            position = self.setting.get(path, 0)
            self.player.setPosition(position)

            # update recent files
            files = self.setting.get("recent_files", [])
            try:
                files.remove(path)
            except ValueError:
                pass
            files.insert(0, path)
            del files[MainWindow.max_recent_files:]
            self.setting["recent_files"] = files
            self.update_recent_file_action()

        # Player state
        state = self.player.state()
        if state in [QMediaPlayer.PausedState, QMediaPlayer.StoppedState]:
            self.btn_play.setIcon(self.ico_play)
            self.timer_learning_time.stop()
        elif state == QMediaPlayer.PlayingState:
            self.btn_play.setIcon(self.ico_pause)
            self.timer_learning_time.start()

    def qmp_position_changed(self, position_ms: int):
        """Handle position of qmedia if the position is changed."""
        if self.pos_loop_b:
            if (position_ms
                    == self.duration_ms) or (self.pos_loop_b < position_ms):
                self.player.setPosition(self.pos_loop_a)
        self.progressbar.setValue(position_ms)
        self.elapsed_time.setText(
            f"{ms2min_sec(position_ms)} / {self.duration_str}")
        self.display_lyrics.update_media_pos(position_ms)

    def qdial_changed(self, pos: int):
        """Handle Qdial position."""
        self.player.setVolume(pos)

    def send_AB_loop_lyrics_to_papago(self):
        """Send AB loop lyrics to papago."""
        if not self.pos_loop_b:
            return
        lyrics = self.display_lyrics.get_lyrics_in_range(
            self.pos_loop_a, self.pos_loop_b)
        lyrics = lyrics.replace("\n", "")
        webbrowser.open(f"https://papago.naver.com/?sk=en&tk=ko&st={lyrics}",
                        autoraise=False)

    @Slot(int)
    def set_media_position(self, position_ms: int):
        """Set the position of Qmedia."""
        self.player.setPosition(position_ms)

    def save_current_media_info(self):
        """Save current media info to setting file."""
        if not osp.isfile(self.path_media):
            return
        if self.path_media:
            position = self.player.position()
            self.setting[self.path_media] = position
            self.setting["LastPlayedPath"] = self.path_media

    def update_learning_time(self):
        """Update learning time."""
        self.learning_time_ms += 1000
        self.learning_time_ms_total += 1000
        self.label_learning_time.setText(
            f"Learning time : {ms2min_sec(self.learning_time_ms)}"
            f" / total : {ms2min_sec(self.learning_time_ms_total)}")

    def closeEvent(self, event):
        """Save setting."""
        self.stop()
        self.setting["learning_time_ms_total"] = self.learning_time_ms_total

        with open("setting.json", "w") as fp:
            json.dump(self.setting, fp, indent=2)

        now = self.now
        cur = sqlite3.connect("history.db")
        cur.execute("CREATE TABLE IF NOT EXISTS LearningTimeData("
                    "DayOfWeek INTEGER, "
                    "month  INTEGER, "
                    "day INTEGER,  "
                    "timestamp REAL, "
                    "LearningTime_ms INTEGER)")
        cur.execute(
            "insert into LearningTimeData Values (?,?,?,?,?)",
            (now.weekday(), now.month, now.day, now.timestamp(),
             self.learning_time_ms),
        )
        cur.commit()
        cur.close()