
Recherche avancée
Autres articles (97)
-
Multilang : améliorer l’interface pour les blocs multilingues
18 février 2011, parMultilang est un plugin supplémentaire qui n’est pas activé par défaut lors de l’initialisation de MediaSPIP.
Après son activation, une préconfiguration est mise en place automatiquement par MediaSPIP init permettant à la nouvelle fonctionnalité d’être automatiquement opérationnelle. Il n’est donc pas obligatoire de passer par une étape de configuration pour cela. -
Gestion des droits de création et d’édition des objets
8 février 2011, parPar défaut, beaucoup de fonctionnalités sont limitées aux administrateurs mais restent configurables indépendamment pour modifier leur statut minimal d’utilisation notamment : la rédaction de contenus sur le site modifiables dans la gestion des templates de formulaires ; l’ajout de notes aux articles ; l’ajout de légendes et d’annotations sur les images ;
-
Dépôt de média et thèmes par FTP
31 mai 2013, parL’outil MédiaSPIP traite aussi les média transférés par la voie FTP. Si vous préférez déposer par cette voie, récupérez les identifiants d’accès vers votre site MédiaSPIP et utilisez votre client FTP favori.
Vous trouverez dès le départ les dossiers suivants dans votre espace FTP : config/ : dossier de configuration du site IMG/ : dossier des média déjà traités et en ligne sur le site local/ : répertoire cache du site web themes/ : les thèmes ou les feuilles de style personnalisées tmp/ : dossier de travail (...)
Sur d’autres sites (10412)
-
ffmpeg : error while loading shared libraries : libvpx.so.6 : cannot open shared object file : No such file or directory
16 avril 2021, par PanosI am building a multi tool discord bot in Python rewrite.


So I decided to add music to it as well. When I completed the bot and tried it on my local pc it worked perfectly. However when I uploaded to Heroku I got some errors for ffmpeg.


Initially I thought Heroku is Linux based so I downloaded ffmpeg for Linux. Still didn't work. Then i added a apt buildpack and downloaded it that way. It worked however now a get a different error. It finds the ffmpeg but the song is not played and this is displayed in the console :




[ffmpeg : error while loading shared libraries : libvpx.so.6 : cannot
open shared object file : No such file or directory]




How can I resolve this issue ?


Here is the whole code :


import discord
from discord.ext import commands

import asyncio
import itertools
import sys
import traceback
from async_timeout import timeout
from functools import partial
from youtube_dl import YoutubeDL
import ctypes
import ctypes.util

@commands.Cog.listener()
async def on_ready(self):

 print("ctypes - Find opus:")
 a = ctypes.util.find_library('opus')
 print(a)
 
 print("Discord - Load Opus:")
 b = discord.opus.load_opus(a)
 print(b)
 
 print("Discord - Is loaded:")
 c = discord.opus.is_loaded()
 print(c)



ytdlopts = {
 'format': 'bestaudio/best',
 'outtmpl': 'downloads/%(extractor)s-%(id)s-%(title)s.%(ext)s',
 'restrictfilenames': True,
 'noplaylist': True,
 'nocheckcertificate': True,
 'ignoreerrors': False,
 'logtostderr': False,
 'quiet': True,
 'no_warnings': True,
 'default_search': 'auto',
 'source_address': '0.0.0.0'
}

ffmpegopts = {
 'before_options': '-nostdin',
 'options': '-vn'
}

ytdl = YoutubeDL(ytdlopts)


class VoiceConnectionError(commands.CommandError):


class InvalidVoiceChannel(VoiceConnectionError):



class YTDLSource(discord.PCMVolumeTransformer):

 def __init__(self, source, *, data, requester):
 super().__init__(source)
 self.requester = requester

 self.title = data.get('title')
 self.web_url = data.get('webpage_url')


 def __getitem__(self, item: str):
 return self.__getattribute__(item)

 @classmethod
 async def create_source(cls, ctx, search: str, *, loop, download=False):
 loop = loop or asyncio.get_event_loop()

 to_run = partial(ytdl.extract_info, url=search, download=download)
 data = await loop.run_in_executor(None, to_run)

 if 'entries' in data:
 data = data['entries'][0]

 await ctx.send(f'```ini\n[Added {data["title"]} to the Queue.]\n```')

 if download:
 source = ytdl.prepare_filename(data)
 else:
 return {'webpage_url': data['webpage_url'], 'requester': ctx.author, 'title': data['title']}

 return cls(discord.FFmpegPCMAudio(source), data=data, requester=ctx.author)

 @classmethod
 async def regather_stream(cls, data, *, loop):
 """Used for preparing a stream, instead of downloading.
 Since Youtube Streaming links expire."""
 loop = loop or asyncio.get_event_loop()
 requester = data['requester']

 to_run = partial(ytdl.extract_info, url=data['webpage_url'], download=False)
 data = await loop.run_in_executor(None, to_run)

 return cls(discord.FFmpegPCMAudio(data['url']), data=data, requester=requester)


class MusicPlayer(commands.Cog):

 __slots__ = ('bot', '_guild', '_channel', '_cog', 'queue', 'next', 'current', 'np', 'volume')

 def __init__(self, ctx):
 self.bot = ctx.bot
 self._guild = ctx.guild
 self._channel = ctx.channel
 self._cog = ctx.cog

 self.queue = asyncio.Queue()
 self.next = asyncio.Event()

 self.np = None
 self.volume = .5
 self.current = None

 ctx.bot.loop.create_task(self.player_loop())

 async def player_loop(self):
 """Our main player loop."""
 await self.bot.wait_until_ready()

 while not self.bot.is_closed():
 self.next.clear()

 try:
 source = await self.queue.get()
 except asyncio.TimeoutError:
 return self.destroy(self._guild)

 if not isinstance(source, YTDLSource):
 try:
 source = await YTDLSource.regather_stream(source, loop=self.bot.loop)
 except Exception as e:
 await self._channel.send(f'There was an error processing your song.\n'
 f'```css\n[{e}]\n```')
 continue

 source.volume = self.volume
 self.current = source

 self._guild.voice_client.play(source, after=lambda _: self.bot.loop.call_soon_threadsafe(self.next.set))
 self.np = await self._channel.send(f'**Now Playing:** `{source.title}` requested by '
 f'`{source.requester}`')
 await self.next.wait()

 source.cleanup()
 self.current = None

 try:
 await self.np.delete()
 except discord.HTTPException:
 pass

 def destroy(self, guild):
 """Disconnect and cleanup the player."""
 return self.bot.loop.create_task(self._cog.cleanup(guild))


class Music(commands.Cog):
 """Music related commands."""

 __slots__ = ('bot', 'players')

 def __init__(self, bot):
 self.bot = bot
 self.players = {}

 async def cleanup(self, guild):
 try:
 await guild.voice_client.disconnect()
 except AttributeError:
 pass

 try:
 del self.players[guild.id]
 except KeyError:
 pass

 async def __local_check(self, ctx):
 """A local check which applies to all commands in this cog."""
 if not ctx.guild:
 raise commands.NoPrivateMessage
 return True

 async def __error(self, ctx, error):
 """A local error handler for all errors arising from commands in this cog."""
 if isinstance(error, commands.NoPrivateMessage):
 try:
 return await ctx.send('This command can not be used in Private Messages.')
 except discord.HTTPException:
 pass
 elif isinstance(error, InvalidVoiceChannel):
 await ctx.send('Error connecting to Voice Channel. '
 'Please make sure you are in a valid channel or provide me with one')

 print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr)
 traceback.print_exception(type(error), error, error.__traceback__, file=sys.stderr)

 def get_player(self, ctx):
 """Retrieve the guild player, or generate one."""
 try:
 player = self.players[ctx.guild.id]
 except KeyError:
 player = MusicPlayer(ctx)
 self.players[ctx.guild.id] = player

 return player

 @commands.command(name='connect', aliases=['join'])
 async def connect_(self, ctx):
 try:
 channel = ctx.author.voice.channel
 except AttributeError:
 raise InvalidVoiceChannel('No channel to join.')

 vc = ctx.voice_client

 if vc:
 if vc.channel.id == channel.id:
 return
 try:
 await vc.move_to(channel)
 except asyncio.TimeoutError:
 raise VoiceConnectionError(f'Moving to channel: <{channel}> timed out.')
 else:
 try:
 await channel.connect()
 except asyncio.TimeoutError:
 raise VoiceConnectionError(f'Connecting to channel: <{channel}> timed out.')

 await ctx.send(f'Connected to: **{channel}**', )

 @commands.command(name='play', aliases=['sing'])
 async def play_(self, ctx, *, search: str):
 await ctx.trigger_typing()

 vc = ctx.voice_client

 if not vc:
 await ctx.invoke(self.connect_)

 player = self.get_player(ctx)
 source = await YTDLSource.create_source(ctx, search, loop=self.bot.loop, download=False)

 await player.queue.put(source)

 @commands.command(name='pause')
 async def pause_(self, ctx):
 """Pause the currently playing song."""
 vc = ctx.voice_client

 if not vc or not vc.is_playing():
 return await ctx.send('I am not currently playing anything!')
 elif vc.is_paused():
 return

 vc.pause()
 await ctx.send(f'**`{ctx.author}`**: Paused the song!')

 @commands.command(name='resume')
 async def resume_(self, ctx):
 """Resume the currently paused song."""
 vc = ctx.voice_client

 if not vc or not vc.is_connected():
 return await ctx.send('I am not currently playing anything!', )
 elif not vc.is_paused():
 return

 vc.resume()
 await ctx.send(f'**`{ctx.author}`**: Resumed the song!')

 @commands.command(name='skip')
 async def skip_(self, ctx):
 """Skip the song."""
 vc = ctx.voice_client

 if not vc or not vc.is_connected():
 return await ctx.send('I am not currently playing anything!')

 if vc.is_paused():
 pass
 elif not vc.is_playing():
 return

 vc.stop()
 await ctx.send(f'**`{ctx.author}`**: Skipped the song!')

 @commands.command(name='queue', aliases=['q', 'playlist'])
 async def queue_info(self, ctx):
 """Retrieve a basic queue of upcoming songs."""
 vc = ctx.voice_client

 if not vc or not vc.is_connected():
 return await ctx.send('I am not currently connected to voice!')

 player = self.get_player(ctx)
 if player.queue.empty():
 return await ctx.send('There are currently no more queued songs.')

 upcoming = list(itertools.islice(player.queue._queue, 0, 5))

 fmt = '\n'.join(f'**`{_["title"]}`**' for _ in upcoming)
 embed = discord.Embed(title=f'Upcoming - Next {len(upcoming)}', description=fmt)

 await ctx.send(embed=embed)

 @commands.command(name='now_playing', aliases=['np', 'current', 'currentsong', 'playing'])
 async def now_playing_(self, ctx):
 """Display information about the currently playing song."""
 vc = ctx.voice_client

 if not vc or not vc.is_connected():
 return await ctx.send('I am not currently connected to voice!', )

 player = self.get_player(ctx)
 if not player.current:
 return await ctx.send('I am not currently playing anything!')

 try:
 await player.np.delete()
 except discord.HTTPException:
 pass

 player.np = await ctx.send(f'**Now Playing:** `{vc.source.title}` '
 f'requested by `{vc.source.requester}`')

 @commands.command(name='volume', aliases=['vol'])
 async def change_volume(self, ctx, *, vol: float):
 """Change the player volume.
 Parameters
 ------------
 volume: float or int [Required]
 The volume to set the player to in percentage. This must be between 1 and 100.
 """
 vc = ctx.voice_client

 if not vc or not vc.is_connected():
 return await ctx.send('I am not currently connected to voice!', )

 if not 0 < vol < 101:
 return await ctx.send('Please enter a value between 1 and 100.')

 player = self.get_player(ctx)

 if vc.source:
 vc.source.volume = vol / 100

 player.volume = vol / 100
 await ctx.send(f'**`{ctx.author}`**: Set the volume to **{vol}%**')

 @commands.command(name='stop', aliases=['leave'])
 async def stop_(self, ctx):
 vc = ctx.voice_client

 if not vc or not vc.is_connected():
 return await ctx.send('I am not currently playing anything!')

 await self.cleanup(ctx.guild)


def setup(client):
 client.add_cog(Music(client))



-
FFmpeg python doesn't merge
24 avril 2021, par MaLoLHDXI was making this youtube downloader GUI with Python : it asks for the URL, gives you a list with the possible quality settings and downloads the selected video file and the best audio file with youtube-dl. However, when I tell ffmpeg to merge the two separate downloaded files, it doesn't do anything and it doesn't say anything in the console either. Is there anything I'm missing ?


Here's the relevant part of the code (starts at line 153) :


#Adding input arguments for ffmpeg
 ffmpeg_video = ffmpeg.input(self.video_title)
 ffmpeg_audio = ffmpeg.input(self.audio_title)
 output_ffmpeg_title = './videos/' + self.youtube_title
 #Merging with ffmpeg
 out = ffmpeg.output(ffmpeg_video, ffmpeg_audio, output_ffmpeg_title, vcodec='copy', acodec='aac')
 out.run



Here's the full code :


import youtube_dl
import tkinter as tk
import operator
import ffmpeg
class GUI:
 def __init__(self):
 #Creating initial window
 self.window = tk.Tk()
 self.window.title('YTDL')
 self.window.geometry('300x70')
 
 self.urlbox = tk.Entry(self.window)
 self.urlbox.pack(padx=5,pady=5)
 #Creating download button, which will open the format selection window
 downbutton = tk.Button(self.window, text="Download", command= self.check_url)
 downbutton.pack(padx=5, pady=5)
 #Creating a variable to keep track of the point in the GUI options selection
 self.format_select_process = False
 
 self.window.mainloop()
 def check_url(self):
 #Saving selected URL to variable
 self.selected_url = self.urlbox.get()
 self.urlbox.delete(0, 'end')
 #If something was written in the URL box, try to go the next step
 if len(self.selected_url) != 0:
 self.get_formats(self.selected_url)
 else:
 print('URL box is empty!')
 def get_formats(self, x):
 with youtube_dl.YoutubeDL() as ydl:
 meta = ydl.extract_info(x, download=False)
 #Save formats from 'meta' to 'self.formats'
 self.formats = meta.get('formats', [meta])
 self.youtube_title = meta.get('title', [meta])
 #Creating two dictionaries for the list of format sizes and extensions
 self.f_list_size_dict = {}
 self.f_list_ext_dict = {}
 #Creating audio format list
 self.audio_format_list = []
 #For every format in self.formats, add its format, extension, fps and filesize to self.f_list
 for f in self.formats:
 self.f_list = '-' + f['format']+ ' -' + f['ext'] + ' -' + str(f['fps']) + ' ' + str(f['filesize'])
 if 'audio only' in f['format']:
 #Add an element to each dictonary whose name is the format ID and whose value is its filesize/extension
 self.f_list_size_dict[f['format'].split(' -')[0]] = f['filesize']
 self.f_list_ext_dict[f['format'].split(' -')[0]] = f['ext']
 #Add to the audio format list the current audio format ID
 self.audio_format_list.append(f['format'].split(' -')[0])
 print('Audio format list:')
 print(self.audio_format_list)
 print('Size list dict:')
 print(self.f_list_size_dict)
 print('Ext list size dict:')
 print(self.f_list_ext_dict)
 """
 #Making a new list which only contains the audio format IDs
 self.audio_format_list = str(self.f_list_size_dict.keys()).split('([')[1]
 self.audio_format_list = self.audio_format_list.split('])')[0]
 self.audio_format_list = self.audio_format_list.replace("'", "")
 self.audio_format_list = self.audio_format_list.split(', ')
 print('Cleaned up audio format list:')
 print(self.audio_format_list)
 """
 #Here the program starts looking for the best audio format
 #In the try block, the program gets the best audio format's ID from the size dict and extension from the ext dict
 #In the except block, the program gets the ID from the audio format list and the extension from the ext dict
 try:
 self.highest_audio = max(self.f_list_size_dict.items(), key=operator.itemgetter(1))[0]
 self.highest_audio_ext = self.f_list_ext_dict.get(self.highest_audio)
 print('Best audio format ID: ' + self.highest_audio)
 print('Best audio format extension: ' + self.highest_audio_ext)
 except:
 self.highest_audio = max(self.audio_format_list)
 self.highest_audio_ext = self.f_list_ext_dict.get(self.highest_audio)
 print(self.highest_audio)
 print(self.highest_audio_ext)
 #Going to next sted of the code, which renders the format choice window
 self.format_select()
 def format_select(self):
 self.window.withdraw()
 format_select_window = tk.Toplevel()
 format_select_window.attributes('-topmost', True)
 format_select_window.geometry("300x350")
 format_select_window_label = tk.Label(format_select_window, text="Select the video format")
 format_select_window_label.pack(padx=5, pady=5)
 format_select_window.protocol('WM_DELETE_WINDOW', lambda: exit())

 self.format_listbox = tk.Listbox(format_select_window, height=15, width=40, yscrollcommand=1)
 self.format_listbox.pack(padx=10, pady=10)
 for index, item in enumerate(self.f_list):
 self.f_list_lenght = index
 download_button = tk.Button(format_select_window, text='Download', command=self.download)
 download_button.pack(padx=10, pady=10)
 #Adding options to the listbox
 for f in self.formats:
 #If it is adding an audio only format, it will add the ID, filesize (if possible with try block) and extension
 if 'audio only' in f['format'] + ' ' + str(f['fps']) + ' FPS ' + f['ext']:
 try:
 mb_filesize = round(f['filesize'] / 1024 / 1024, 2)
 self.format_listbox.insert(self.f_list_lenght, f['format'] + ' ' + str(mb_filesize) + ' MiB ' + f['ext']) 
 except:
 self.format_listbox.insert(self.f_list_lenght, f['format'] + ' ' + f['ext'])
 #If it is adding a video format, it will add the ID, FPS, filesize (if possible with the try block) and extension
 else:
 try:
 mb_filesize = round(f['filesize'] / 1024 / 1024, 2)
 self.format_listbox.insert(self.f_list_lenght, f['format'] + ' ' + str(f['fps']) + ' FPS' + ' ' + str(mb_filesize) + ' MiB ' + f['ext'])
 except:
 self.format_listbox.insert(self.f_list_lenght, f['format'] + ' ' + str(f['fps']) + ' FPS ' + f['ext'])
 def download(self):
 #Getting the list position of the selected format
 selected_format_list_position = self.format_listbox.curselection()
 #Getting the text of the selected format list item
 selected_format = self.format_listbox.get(selected_format_list_position)
 print('Selected format: ' + selected_format)
 #Cutting from the selected format list item text everything past ' -' to only get the format's ID
 selected_format_id = selected_format.split(' -')[0]
 print('Selected format ID: ' + selected_format_id)
 #Converting the ID to string
 final_selected_format_id = str(selected_format_id)
 print('Final selected format: ' + final_selected_format_id)
 #Cutting from the selected format list item text everything before ' ' to only get the extension
 final_ext = selected_format.split(' ')[1]
 print('Final video extension: ' + final_ext)
 if 'audio only' in selected_format:
 #Creating the download options dictionary (not working):
 #Setting the download location to the videos folder,
 #preventing the program from downloading a whole playlist,
 #telling youtube-dl to extract audio ('x'),
 #giving youtube-dl the requested format (which is only audio).
 self.ydl_opts = {'outtmpl':'./videos/%(title)s.%(ext)s', 'noplaylist': True, 'x': True, 'format': final_selected_format_id}
 #Downloading
 with youtube_dl.YoutubeDL(self.ydl_opts) as ydl:
 ydl.download([self.selected_url])
 elif 'audio only' not in selected_format:
 #Adding '+bestaudio' to the selected format ID (which is only a video ID in this case)
 final_selected_format_id_video_audio = str(selected_format_id) + '+bestaudio'
 #Creating the download options dictionary:
 #Setting the download location to the videos folder,
 #preventing the program from downloading a whole playlist,
 #giving youtube-dl the requested format with audio.
 self.ydl_opts = {'outtmpl':'./videos/%(title)s.%(ext)s', 'noplaylist': True, 'format': final_selected_format_id_video_audio}
 #Predicting the video file title and location for future ffmpeg merge
 self.video_title = './videos/' + self.youtube_title + '.f' + str(selected_format_id) + '.' + final_ext
 print('Video file title: ' + self.video_title)
 #Predicting the audio file title and location for future ffmpeg merge
 self.audio_title = './videos/' + self.youtube_title + '.f' + str(self.highest_audio) + '.' + self.highest_audio_ext
 print('Audio file title: ' + self.audio_title)
 #Downloading with youtube-dl
 with youtube_dl.YoutubeDL(self.ydl_opts) as ydl:
 ydl.download([self.selected_url])
 #Adding input arguments for ffmpeg
 ffmpeg_video = ffmpeg.input(self.video_title)
 ffmpeg_audio = ffmpeg.input(self.audio_title)
 output_ffmpeg_title = './videos/' + self.youtube_title
 #Merging with ffmpeg
 ffmpeg.output(ffmpeg_video, ffmpeg_audio, output_ffmpeg_title, vcodec='copy', acodec='aac')
GUI()



If there is a better way of integrating ffmpeg with youtube-dl in Python, please tell me.


-
How to set output file while using subprocess.Popen and hide cmd window at the same time ?
2 mars 2021, par NandeI made a simple app that can convert video files using FFMpeg. I used Kivy for UI. I used
os.system()
to execute ffmpeg commands but while using this method, there is always a cmd window popping up. Therefore i am trying to usesubprocess.Popen()
to execute ffmpeg commands but i also want to save ffmpeg output to a text file.

I tried this but it didn't work :


subprocess.Popen(f"ffmpeg -i {path} -acodec {acodec} {output} > output.txt 2>&1", creationflags = 0x08000000, stdout="output.txt")



FFMpeg converts the video but there is no output.txt file. This code works with
os.system()


How can i hide cmd window while saving output to a text file ?


My full python code :


import os
from signal import SIGINT
import psutil
from time import sleep
from threading import Thread
from kivy.config import Config
Config.set('graphics', 'resizable', False)
Config.set('graphics', 'width', '400')
Config.set('graphics', 'height', '330')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.uix.popup import Popup
from kivy.properties import ObjectProperty

Window.clearcolor = (1, 1, 1, 1)

desktop = os.path.join(os.path.join(os.path.expanduser('~')), 'Desktop') + "\\"


def cmd(command):
 os.system(command)


def getpid(prcs):
 for proc in psutil.process_iter():
 try:
 pinf = proc.as_dict(attrs=["pid", "name"])
 if prcs.lower() in pinf["name"].lower():
 return pinf["pid"]
 except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
 return False
 return False


# noinspection PyGlobalUndefined
def progress(app, path):
 app.root.prgrss_bar.value = 0
 app.root.prgrss_lbl.text = "Progress: %0"

 if not os.getcwd().endswith("ffmpeg"):
 os.chdir("ffmpeg")

 inputpath = app.root.label.text
 if inputpath.startswith("Choose"):
 return
 audio = app.root.audio.state
 video = app.root.video.state
 both = app.root.both.state

 global line1
 global line2

 if video == "down" or both == "down":
 command = f"ffprobe -v error -select_streams v:0 -show_entries stream=nb_frames -of default=nokey=1:noprint_wrappers=1 {inputpath} > output2.txt 2>&1"
 os.system(command)
 ffprobe = open("output2.txt", "r")
 frames = int(ffprobe.read())

 control = True
 while control:
 sleep(0.5)

 with open(path, "r") as f:
 for last_line in f:
 pass
 line1 = last_line
 sleep(0.5)

 with open(path, "r") as f:
 for last_line in f:
 pass
 line2 = last_line
 if line1 == line2:
 app.root.prgrss_bar.value = 100
 app.root.prgrss_lbl.text = "Progress: Finished"
 control = False
 else:
 try:
 current_frame = int(line2.split("=")[1].split()[0])
 percentage = int(current_frame / frames * 100)
 text = f"Progress: %{percentage}"
 app.root.prgrss_lbl.text = text
 app.root.prgrss_bar.value = percentage
 if percentage == 100:
 control = False
 except ValueError or TypeError:
 pass

 elif audio == "down":
 command = f"ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 {app.root.label.text} > output2.txt 2>&1"
 os.system(command)
 ffprobe = open("output2.txt", "r")
 duration = round(float(ffprobe.read()), 2)
 control = True
 while control:
 sleep(0.5)
 with open(path, "r") as f:
 for last_line in f:
 pass
 line1 = last_line
 sleep(0.5)

 with open(path, "r") as f:
 for last_line in f:
 pass
 line2 = last_line
 if line1 == line2:
 app.root.prgrss_bar.value = 100
 app.root.prgrss_lbl.text = "Progress: Finished"
 control = False
 else:
 try:
 current = line2.split("=")[2].split()[0].split(":")
 seconds = round((int(current[0]) * 3600) + (int(current[1]) * 60) + float(current[2]), 2)
 percentage = int(seconds / duration * 100)
 text = f"Progress: %{percentage}"
 app.root.prgrss_lbl.text = text
 app.root.prgrss_bar.value = percentage
 if percentage == 100:
 control = False
 except ValueError or TypeError:
 pass


class Window(Widget):

 @staticmethod
 def popup_open():
 popup = FolderPopup()
 popup.open()

 @staticmethod
 def exists_open():
 popup = Exists()
 popup.open()

 @staticmethod
 def choose_open():
 popup = ChooseFormat()
 popup.open()

 @staticmethod
 def path_popup():
 popup = ChoosePath()
 popup.open()

 @staticmethod
 def unsupported_audio():
 popup = UnsupportedAudio()
 popup.open()

 @staticmethod
 def no_video_format():
 popup = NoVideoFormat()
 popup.open()

 @staticmethod
 def no_process():
 popup = NoFFMPEGProcess()
 popup.open()

 def start(self, app):
 path = app.root.label.text
 if path.startswith("Choose"):
 self.path_popup()
 return

 outname = app.root.outname.text
 video_f = app.root.spinner.text
 audio_f = app.root.spinner2.text
 video = app.root.video.state
 audio = app.root.audio.state
 both = app.root.both.state

 audio_supported = {"MP4": ["AAC", "MP3", "Opus"],
 "MKV": ["AAC", "MP3", "Opus"],
 "MOV": ["AAC", "MP3"],
 "AVI": ["AAC", "MP3"],
 "WMV": ["AAC", "MP3"]}

 audio_ce = {"AAC": ["aac", ".m4a"],
 "MP3": ["libmp3lame", ".mp3"],
 "Opus": ["libopus", ".opus"],
 "WAV": ["pcm_u8", ".wav"],
 "Choose": ["Choose", "Choose"]}

 if not os.getcwd().endswith("ffmpeg"):
 os.chdir("ffmpeg")

 video_ext = video_f.lower()
 acodec = audio_ce[audio_f][0]
 audio_ext = audio_ce[audio_f][1]
 command = ""

 if (video == "normal" and audio == "normal" and both == "normal") or (
 video_f == "Choose" and audio_f == "Choose"):
 self.choose_open()
 return
 elif video == "down":
 if video_f == "Choose":
 self.no_video_format()
 return
 output = f"{desktop}{outname}.{video_ext}"
 if not os.path.exists(output):
 command += f"ffmpeg -i {path} -an {output} > output.txt 2>&1"
 else:
 self.exists_open()
 return
 elif audio == "down":
 output = f"{desktop}{outname}{audio_ext}"
 if not os.path.exists(output):
 command += f"ffmpeg -i {path} -vn -acodec {acodec} {output} > output.txt 2>&1"
 else:
 self.exists_open()
 return
 elif both == "down":
 if video_f == "Choose":
 self.no_video_format()
 return
 elif audio_f == "Choose":
 output = f"{desktop}{outname}.{video_ext}"
 if not os.path.exists(output):
 command += f"ffmpeg -i {path} {output} > output.txt 2>&1"
 else:
 self.exists_open()
 return
 else:
 if audio_f not in audio_supported[video_f]:
 self.unsupported_audio()
 return
 else:
 output = f"{desktop}{outname}.{video_ext}"
 if not os.path.exists(output):
 command += f"ffmpeg -i {path} -acodec {acodec} {output} > output.txt 2>&1"
 else:
 self.exists_open()
 return

 thrd = Thread(target=cmd, args=(command,))
 thrd.start()
 print("Thread started.")

 def stop(self):
 pid = getpid("ffmpeg")
 if not pid:
 self.no_process()
 else:
 os.kill(pid, SIGINT)

 def test_open(self, app):
 if not os.getcwd().endswith("ffmpeg"):
 os.chdir("ffmpeg")

 video = app.root.label.text
 if video.startswith("Choose"):
 return self.path_popup()

 command = f"ffplay {video}"
 os.system(command)

 @staticmethod
 def check_progress(app):
 path = os.getcwd() + r"\output.txt"
 chkprgrss = Thread(target=progress, args=(app, path,))
 chkprgrss.start()


class FolderPopup(Popup):
 dosya = ObjectProperty(None)
 desktop = desktop

 @staticmethod
 def no_path_submit():
 popup = NoPathSubmit()
 popup.open()

 def buton(self, app):

 try:
 app.root.label.text = self.dosya.selection[0]
 self.dismiss()
 except:
 self.no_path_submit()


class Exists(Popup):
 def buton(self):
 self.dismiss()


class ChooseFormat(Popup):
 def buton(self):
 self.dismiss()


class ChoosePath(Popup):
 def buton(self):
 self.dismiss()


class UnsupportedAudio(Popup):
 def buton(self):
 self.dismiss()


class NoVideoFormat(Popup):
 def buton(self):
 self.dismiss()


class NoPathSubmit(Popup):
 def buton(self):
 self.dismiss()


class NoFFMPEGProcess(Popup):
 def buton(self):
 self.dismiss()


class GUI(App):
 def build(self):
 return Window()


if __name__ == "__main__":
 GUI().run()