gh37pt_chr
@gh37pt_chr

Как принудительно завершить дополнительный поток (thread)?

import threading
import time
import customtkinter
import vlc
import json
import sys
import stopit
from tkinter import filedialog
from PIL import Image
from side_files.get_track_metadata import get_track_title, get_track_artist, get_track_comment
from side_files.add_new_tracks import add_tracks_in_playlist
from side_files.time_counting import time_count

class Phxnk_Mxster:
    def __init__(self):
        self.window = customtkinter.CTk()
        self.window.geometry("1000x850")
        self.window.title("Phxnk Mxster")
        self.tracks_on_main_frame_list = []
        self.button_list = []
        self.track_path_list = []
        self.track_names_list = []
        self.player = vlc.MediaPlayer()
        #self.stop_thread = False
        #self.counting_time_cycle = None

    def initialize_interface(self):
        self.scrollable_frame = customtkinter.CTkScrollableFrame(self.window, width=800, height=700, fg_color="#080808")
        self.scrollable_frame.place(x=-1, y=-1)

        self.default_music_image = customtkinter.CTkImage(dark_image=Image.open("assets/default_music_icon.png"), size=(85, 85))
        self.lab = customtkinter.CTkLabel(self.window, image=self.default_music_image, text="")
        self.lab.place(x=100, y=737)

        self.next_button_image = customtkinter.CTkImage(dark_image=Image.open("assets/next.png"), size=(81, 78))
        self.next_button = customtkinter.CTkButton(self.window, image=self.next_button_image, width=82, height=82, corner_radius=0, text="", fg_color="transparent",hover_color="#636363")
        self.next_button.place(x=200, y=736)

        self.previous_button_image = customtkinter.CTkImage(dark_image=Image.open("assets/previous.png"), size=(81, 78))
        self.previous_button = customtkinter.CTkButton(self.window, image=self.previous_button_image, width=82, height=82, corner_radius=0, text="", fg_color="transparent", hover_color="#636363")
        self.previous_button.place(x=0, y=736)

        self.volume_slider = customtkinter.CTkSlider(self.window, from_=0, to=100, orientation="vertical", command=self.change_track_volume)
        self.volume_slider.place(x=950, y=580)

        try:
            with open('data/settings.json', 'r') as value:
                loaded_volume_data = json.load(value)
            volume_value = loaded_volume_data.get("volume")
            self.volume_slider.set(int(volume_value))

        except:
            self.volume_slider.set(0)

        print(f"Current colume - {volume_value}")

        self.time_slider = customtkinter.CTkSlider(self.window, from_=0, to=100, width=500)
        self.time_slider.place(x=300, y=760)
        #self.time_slider.bind("<ButtonRelease-1>", self.time_slider_change)
        self.time_slider.set(0)

        self.exit_button = customtkinter.CTkButton(self.window, text="Выход", command=sys.exit)
        self.exit_button.place(x=840, y=800)

        self.add_track_button = customtkinter.CTkButton(self.window, text="Добавить музыку", command=lambda: self.add_tracks_in_main_playlist())
        self.add_track_button.place(x=840, y=25)

        self.now_playing_track_label = customtkinter.CTkLabel(self.window, text="Сейчас играет: ", font=("Arial Bold", 16))
        self.now_playing_track_label.place(x=305, y=800)

        self.track_label = customtkinter.CTkLabel(self.window, text="")
        self.track_label.place(x=440, y=800)

        print("Interface initialized.\n")


    def add_tracks_in_main_playlist(self):
        paths_of_choosed_tracks = filedialog.askopenfilenames(title="Выберите треки", filetypes=[("Аудиофайлы", "*.mp3")])
        add_tracks_in_playlist(self, master=self.scrollable_frame, paths=paths_of_choosed_tracks)


    def play_choosed_track(self, current_track):
        #self.stop_thread = True
        self.player.stop()

        self.player = vlc.MediaPlayer(current_track)
        self.player.play()

        print(f"Player has started playing  '{get_track_artist(self, audio_file_path=current_track)} - {get_track_title(self, audio_file_path=current_track)}'")

        #if self.counting_time_cycle:
            #self.stop_thread = True
            #self.counting_time_cycle.join()

        self.counting_time_cycle = threading.Thread(target=self.time_count, daemon=True)
        self.counting_time_cycle.start()


    def time_count(self):
        while True:
            if self.player.get_time() > 0 and self.player.get_length() > 0:

                self.current_time = int((self.player.get_time() / 1000))
                self.total_time = int(self.player.get_length() / 1000)
                # self.player_state = player.is_playing()

                self.time_slider.configure(from_=0, to=self.total_time)
                self.time_slider.set(self.current_time)

                print(f"Current track time - {self.current_time}s., total track time - {self.total_time}s.")
                print(f"Current state of player - {self.player.get_state()}")
                # print(player.is_playing())

                time.sleep(1)

                if self.current_time == self.total_time:
                    self.player.stop()
                    self.time_slider.configure(from_=0, to=100)
                    self.time_slider.set(0)
                    print("Current media file is completed.")
                    break


    def change_track_volume(self, value):
        self.player.audio_set_volume(int(value))
        print(f"Volume chaged to {int(value)}")

        with open('data/settings.json', 'r') as json_file:
            data = json.load(json_file)

        data['volume'] = int(value)

        with open('data/settings.json', 'w') as json_file:
            json.dump(data, json_file, indent=4)


phxnk_mxster_app = Phxnk_Mxster()
phxnk_mxster_app.initialize_interface()
phxnk_mxster_app.window.mainloop()


"play_choosed_track" проигрывает аудиофайл и в качестве доп. потока вызывает функцию "time_count", что циклично отслеживает время. Проигрывается аудиофайл, поток "time_count", запускается и отслеживает текущее и конечное время аудиофайла. Проблема в том, что если во время воспроизведения аудиофайла сразу начать проигрывать другой, то предыдущий доп. поток не завершается, запускается новый доп. поток, и так по нарастающей: Создаются новые потоки, оперативка засоряется, проц охреневает. Какой-нибудь "thread.stop()" не существует во имя безопасности оперативки, библиотека "stopit" не выполняет своей задачи. Мне нужно, что бы предыдущий поток завершался, если плеер уже проигрывает аудиофайл, (Или какую-то альтернативу, со схожим функционалом), что бы эти злополучные потоки отстали уже от моей оперативочки, но при этом прилежно вкалывали, если плеер ничего не проигрывает. Очень надеюсь именно на вашу помощь.
  • Вопрос задан
  • 55 просмотров
Пригласить эксперта
Ответы на вопрос 1
Vindicar
@Vindicar
RTFM!
Просто прибить поток технически можно, но на практике чревато - нет способа контроля за тем, когда поток прибьётся, так что если это произойдёт в неподходящий момент, внутренняя машинерия питона может сломаться.

Лучше проектируй свой счётчик времени, что тут скажешь. Хотя я бы лучше само воспроизведение звука вынес бы в отдельный поток, а главный поток пускай занимается трекингом.

Пример, как можно сделать поток с ожиданием И быстрым прибитием.
def long_worker_thread(event: threading.Event):
    ...  # тут начальная подготовка. имей ввиду, что цикл начнётся с ожидания
    while not event.wait(1.0):  # ждём пока пройдёт заданное время - или пока event не будет взведено
        ...  # тут работу работаем - но не слишком долго, чтобы проверки event.wait() делались регулярно!
    ...  # завершение. Произойдёт, если был сделан break, или если event было взведено

stop_worker = threading.Event()
thread = threading.Thread(target=long_worker_thread, args=(stop_worker,))
thread.start()
...  # что-то делаем пока поток крутится
stop_worker.set()  # ожидание в потоке прервётся немедленно, не дожидаясь конца интервала
thread.join()  # поэтому можно спокойно дождаться, пока поток не закончит работу - это будет быстро
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы