From d59fc7c0e7a4110a69994ef2ca3feb94ed12947f Mon Sep 17 00:00:00 2001 From: Sergio Costas Date: Thu, 17 Jul 2014 00:21:36 +0200 Subject: [PATCH] Now stores and recovers all the file properties More changes in the interface to allow a better workflow Started support for Matroska and H.264 --- data/interface/wfile_properties.ui | 705 ++++++++++++------ data/interface/wselect_disk.ui | 52 +- data/pixmaps/icon_mkv.png | Bin 0 -> 3898 bytes src/devede/add_files.py | 8 - .../{convert.py => avconv_converter.py} | 15 +- src/devede/check_binaries.py | 48 ++ src/devede/choose_disc_type.py | 66 ++ src/devede/configuration_data.py | 82 +- src/devede/converter.py | 115 +++ src/devede/executor.py | 32 + src/devede/file_movie.py | 263 +++++-- src/devede/interface_manager.py | 266 +++++++ src/devede/mpv_converter.py | 105 +++ src/devede/project.py | 151 ++-- src/devede_ng.py | 5 +- 15 files changed, 1495 insertions(+), 418 deletions(-) create mode 100644 data/pixmaps/icon_mkv.png rename src/devede/{convert.py => avconv_converter.py} (75%) create mode 100644 src/devede/check_binaries.py create mode 100644 src/devede/choose_disc_type.py create mode 100644 src/devede/converter.py create mode 100644 src/devede/executor.py create mode 100644 src/devede/interface_manager.py create mode 100644 src/devede/mpv_converter.py diff --git a/data/interface/wfile_properties.ui b/data/interface/wfile_properties.ui index 9b1dfac..54ab0c9 100644 --- a/data/interface/wfile_properties.ui +++ b/data/interface/wfile_properties.ui @@ -2,47 +2,56 @@ - + + -30 + 30 + 1 + 10 + + 128 448 224 32 64 - + 1 100 5 1 10 - - -30 - 30 - 1 - 10 + + + + + + + + + - + 10 50 - 28 + 10 1 10 - + 400 8500 5000 1 100 - + 300 100 1 10 - False True @@ -77,7 +86,7 @@ False 12 - + True True @@ -111,7 +120,7 @@ False 12 - + True False 0 @@ -198,7 +207,7 @@ - + True False 0 @@ -239,7 +248,7 @@ - + True False 0 @@ -266,7 +275,7 @@ - + True False 0 @@ -279,7 +288,7 @@ - + True False 0 @@ -321,7 +330,7 @@ - + True False 0 @@ -334,7 +343,7 @@ - + True False 0 @@ -377,7 +386,7 @@ False 12 - + True True @@ -406,7 +415,7 @@ False vertical - + PAL/SECAM True True @@ -422,14 +431,14 @@ - + NTSC True True False 0 True - radiobutton_pal + format_pal False @@ -477,11 +486,11 @@ True False - + True True vertical - adjustment_volume + volume True False @@ -493,12 +502,12 @@ - + True True 300 number - adjustment_volume + volume 300 @@ -509,7 +518,7 @@ - + Reset True True @@ -543,7 +552,7 @@ - + True False 2 @@ -558,10 +567,42 @@ False 12 - + True - True - adjustment_video + False + + + Automatic + True + True + False + 0 + True + + + False + True + 0 + + + + + True + True + 5 + 7 + 5000 + 1 + video_rate + 5000 + + + False + True + 4 + 1 + + @@ -583,7 +624,7 @@ - + True False 2 @@ -598,10 +639,41 @@ False 12 - + True - True - adjustment_audio + False + + + Automatic + True + True + False + 0 + True + + + False + True + 0 + + + + + True + True + 7 + 224 + 1 + audio_rate + 224 + + + False + True + 4 + 1 + + @@ -623,7 +695,7 @@ - + True False 2 @@ -659,11 +731,11 @@ - + True True 5 - adjustment_chapter_size + chapter_size 1 5 @@ -733,13 +805,37 @@ always in - + True True liststore_subs + False + False + + + Language + + + + 2 + + + + + + + Subtitle + + + + 0 + + + + @@ -766,10 +862,10 @@ - + True True - adjustment_font + subt_font_size False @@ -798,7 +894,7 @@ False end - + gtk-add True True @@ -812,7 +908,7 @@ - + gtk-delete True True @@ -861,7 +957,7 @@ False 16 - + True False 0 @@ -872,162 +968,326 @@ False 12 - + True False + vertical - - Automatic - True - True - False - 0 - True - True - - - 0 - 0 - 1 - 1 - - - - - 1920x1080 - True - True - False - 0 - True - True - size_auto - - - 1 - 0 - 1 - 1 - - - - - 1280x720 - True - True - False - 0 - True - True - size_auto - - - 2 - 0 - 1 - 1 - - - - - 720x576 - True - True - False - 0 - True - True - size_auto - - - 0 - 1 - 1 - 1 - - - - - 704x576 - True - True - False - 0 - True - True - size_auto - - - 1 - 1 - 1 - 1 - - - - - 480x576 - True - True - False - 0 - True - True - size_auto - - - 2 - 1 - 1 - 1 - - - - - 352x576 - True - True - False - 0 - True - True - size_auto - - - 0 - 2 - 1 - 1 - - - - - 352x288 - True - True - False - 0 - True - True - size_auto - - - 1 - 2 - 1 - 1 - - - - + True False + + + Automatic + True + True + False + 0 + True + True + + + 0 + 0 + 1 + 1 + + + + + 1920x1080 + True + True + False + 0 + True + size_auto_ntsc + + + 1 + 0 + 1 + 1 + + + + + 1280x720 + True + True + False + 0 + True + size_auto_ntsc + + + 2 + 0 + 1 + 1 + + + + + 720x480 + True + True + False + 0 + True + size_auto_ntsc + + + 0 + 1 + 1 + 1 + + + + + 704x480 + True + True + False + 0 + True + size_auto_ntsc + + + 1 + 1 + 1 + 1 + + + + + 480x480 + True + True + False + 0 + True + size_auto_ntsc + + + 2 + 1 + 1 + 1 + + + + + 352x480 + True + True + False + 0 + True + size_auto_ntsc + + + 0 + 2 + 1 + 1 + + + + + 352x240 + True + True + False + 0 + True + size_auto_ntsc + + + 1 + 2 + 1 + 1 + + + + + True + False + + + 2 + 2 + 1 + 1 + + - 2 - 2 - 1 - 1 + False + True + 0 + + + + + True + False + + + Automatic + True + True + False + 0 + True + True + + + 0 + 0 + 1 + 1 + + + + + 1920x1080 + True + True + False + 0 + True + size_auto + + + 1 + 0 + 1 + 1 + + + + + 1280x720 + True + True + False + 0 + True + size_auto + + + 2 + 0 + 1 + 1 + + + + + 720x576 + True + True + False + 0 + True + size_auto + + + 0 + 1 + 1 + 1 + + + + + 704x576 + True + True + False + 0 + True + size_auto + + + 1 + 1 + 1 + 1 + + + + + 480x576 + True + True + False + 0 + True + size_auto + + + 2 + 1 + 1 + 1 + + + + + 352x576 + True + True + False + 0 + True + size_auto + + + 0 + 2 + 1 + 1 + + + + + 352x288 + True + True + False + 0 + True + size_auto + + + 1 + 2 + 1 + 1 + + + + + True + False + + + 2 + 2 + 1 + 1 + + + + + False + True + 1 @@ -1051,7 +1311,7 @@ - + True False 0 @@ -1206,7 +1466,7 @@ - + True False gtk-missing-image @@ -1219,7 +1479,7 @@ - + True False gtk-missing-image @@ -1232,7 +1492,7 @@ - + True False gtk-missing-image @@ -1543,7 +1803,7 @@ - TADIF deinterlacing filter + YADIF deinterlacing filter True True False @@ -1626,10 +1886,10 @@ - + True True - adjustment_delay + audio_delay 1 @@ -1720,7 +1980,7 @@ False vertical - + Stop reproduction/show disc menu True True @@ -1736,14 +1996,14 @@ - + Play the first title True True False 0 True - stop + action_stop False @@ -1752,14 +2012,14 @@ - + Play the previous title True True False 0 True - stop + action_stop False @@ -1768,14 +2028,14 @@ - + Play this title again (loop) True True False 0 True - stop + action_stop False @@ -1784,14 +2044,14 @@ - + Play the next title True True False 0 True - stop + action_stop False @@ -1800,14 +2060,14 @@ - + Play the last title True True False 0 True - stop + action_stop False @@ -1890,7 +2150,7 @@ - + Use a GOP of 12 frames (improves compatibility) True True @@ -1946,13 +2206,13 @@ - False + True True 2 - + Preview True True @@ -2024,20 +2284,9 @@ - - 160x120 - True - True - False - 0 - 0.52999997138977051 - True - True - size_auto - - + diff --git a/data/interface/wselect_disk.ui b/data/interface/wselect_disk.ui index e983b60..5a24485 100644 --- a/data/interface/wselect_disk.ui +++ b/data/interface/wselect_disk.ui @@ -4,9 +4,12 @@ False + False + True center devede.svg - + False + False True @@ -261,6 +264,53 @@ Creates files compliant with DivX home players 5 + + + True + True + True + + + + True + False + + + True + False + icon_mkv.png + + + False + True + 0 + + + + + True + False + 0 + <b>Matroska / H.264</b> +Creates H.264 files in a MKV container + True + + + True + True + 4 + 1 + + + + + + + True + True + 6 + + diff --git a/data/pixmaps/icon_mkv.png b/data/pixmaps/icon_mkv.png new file mode 100644 index 0000000000000000000000000000000000000000..ec95f6c0892b52fee9b1501bf88be0c9fa58dfeb GIT binary patch literal 3898 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 Dp?Pwb literal 0 HcmV?d00001 diff --git a/src/devede/add_files.py b/src/devede/add_files.py index 3339d73..83f7b9b 100644 --- a/src/devede/add_files.py +++ b/src/devede/add_files.py @@ -26,14 +26,6 @@ class add_files: def __init__(self): self.config = devede.configuration_data.configuration.get_config() - self.show_title_options = True - - def set_type(self,disc_type): - - if (disc_type == "dvd"): - self.show_title_options = True - else: - self.show_title_options = False def run(self): diff --git a/src/devede/convert.py b/src/devede/avconv_converter.py similarity index 75% rename from src/devede/convert.py rename to src/devede/avconv_converter.py index 5ce867c..ba8271e 100644 --- a/src/devede/convert.py +++ b/src/devede/avconv_converter.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 + # Copyright 2014 (C) Raster Software Vigo (Sergio Costas) # # This file is part of DeVeDe-NG @@ -15,5 +17,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see -def test(): - print("Test function2") \ No newline at end of file +import subprocess + +import devede.configuration_data + +class avconv_converter: + + def __init__(self): + + self.config = devede.configuration_data.configuration.get_config() + + \ No newline at end of file diff --git a/src/devede/check_binaries.py b/src/devede/check_binaries.py new file mode 100644 index 0000000..f31586c --- /dev/null +++ b/src/devede/check_binaries.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 + +# Copyright 2014 (C) Raster Software Vigo (Sergio Costas) +# +# This file is part of DeVeDe-NG +# +# DeVeDe-NG is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# DeVeDe-NG is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + +import subprocess + +import devede.configuration_data + +class check_binaries: + + def __init__(self): + + self.config = devede.configuration_data.configuration.get_config() + + self.check_mplayer() + self.check_mpv() + + + def check_mplayer(self): + + handle = subprocess.Popen(["mplayer","-v"]) + if 0==handle.wait(): + self.config.mplayer_available = True + else: + self.config.mplayer_available = False + + def check_mpv(self): + + handle = subprocess.Popen(["mpv","-v"]) + if 0==handle.wait(): + self.config.mpv_available = True + else: + self.config.mpv_available = False \ No newline at end of file diff --git a/src/devede/choose_disc_type.py b/src/devede/choose_disc_type.py new file mode 100644 index 0000000..ad426f2 --- /dev/null +++ b/src/devede/choose_disc_type.py @@ -0,0 +1,66 @@ +# Copyright 2014 (C) Raster Software Vigo (Sergio Costas) +# +# This file is part of DeVeDe-NG +# +# DeVeDe-NG is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# DeVeDe-NG is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + +from gi.repository import Gtk,GObject +import os + +import devede.configuration_data + +class choose_disc_type(GObject.GObject): + + def __init__(self): + + self.config = devede.configuration_data.configuration.get_config() + + builder = Gtk.Builder() + builder.set_translation_domain(self.config.gettext_domain) + + builder.add_from_file(os.path.join(self.config.glade,"wselect_disk.ui")) + builder.connect_signals(self) + self.wask_window = builder.get_object("wselect_disk") + self.wask_window.show_all() + + def set_type(self,disc_type): + + self.config.set_disc_type(disc_type) + self.wask_window.hide() + self.wask_window.destroy() + self.wask_window = None + + def on_button_dvd_clicked(self,b): + + self.set_type("dvd") + + def on_button_vcd_clicked(self,b): + + self.set_type("vcd") + + def on_button_svcd_clicked(self,b): + + self.set_type("svcd") + + def on_button_cvd_clicked(self,b): + + self.set_type("cvd") + + def on_button_divx_clicked(self,b): + + self.set_type("divx") + + def on_button_mkv_clicked(self,b): + + self.set_type("mkv") diff --git a/src/devede/configuration_data.py b/src/devede/configuration_data.py index 3aacb1b..2904ab9 100644 --- a/src/devede/configuration_data.py +++ b/src/devede/configuration_data.py @@ -17,38 +17,45 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see +from gi.repository import GObject import os -class configuration: +class configuration(GObject.GObject): current_configuration = None + __gsignals__ = {'disc_type': (GObject.SIGNAL_RUN_FIRST, None,(str,))} @staticmethod def get_config(): if configuration.current_configuration == None: configuration.current_configuration = configuration() + if (configuration.current_configuration.fill_config()): + configuration.current_configuration = None return configuration.current_configuration - def __init__(self): + def fill_config(self): + + GObject.GObject.__init__(self) - self.error = False is_local = None + self.log = "" + self.disc_type = None try: os.stat("/usr/share/devede_ng/wselect_disk.ui") is_local = False except: pass - + if is_local == None: try: os.stat("/usr/local/share/devede_ng/wselect_disk.ui") is_local = True except: pass - + if is_local == None: - self.error = True + return True else: if (is_local): # locales must be always at /usr/share/locale because Gtk.Builder always search there @@ -74,6 +81,11 @@ class configuration: self.final_folder = None self.sub_language = None self.sub_codepage = None + self.film_analizer = None + self.film_player = None + self.film_converter = None + self.menu_converter = None + self.subtitles_font_size = 28 config_path = os.path.join(os.environ.get("HOME"),".devede") try: @@ -87,29 +99,54 @@ class configuration: if linea[:13]=="video_format:": if linea[13:].strip() =="pal": self.PAL=True - continue - if linea[13:].strip()=="ntsc": + elif linea[13:].strip()=="ntsc": self.PAL=False - continue + continue if linea[:12]=="temp_folder:": self.tmp_folder=linea[12:].strip() + continue if linea[:10]=="multicore:": if linea[10:].strip()=="1": self.multicore = False else: self.multicore = True + continue if linea[:13]=="final_folder:": self.final_folder=linea[13:].strip() + continue if linea[:13]=="sub_language:": self.sub_language=linea[13:].strip() + continue if linea[:13]=="sub_codepage:": self.sub_codepage=linea[13:].strip() + continue + if linea[:14]=="film_analizer:": + self.film_analizer = linea[14:].strip() + continue + if linea[:12]=="film_player:": + self.film_player = linea[12:].strip() + continue + if linea[:15]=="film_converter:": + self.film_converter = linea[15:].strip() + continue + if linea[:15]=="menu_converter:": + self.menu_converter = linea[15:].strip() + continue + if linea[:19]=="subtitle_font_size:": + self.subtitles_font_size = int(linea[19:].strip()) config_data.close() except: pass - + + return False + + def set_disc_type(self,disc_type): + + self.disc_type = disc_type + self.emit('disc_type',disc_type) + def save_config(self): - + config_path = os.path.join(os.environ.get("HOME"),".devede") try: config_data = open(config_path,"w") @@ -131,6 +168,29 @@ class configuration: config_data.write("sub_language:"+str(self.sub_language)+"\n") if (self.sub_codepage != None): config_data.write("sub_codepage:"+str(self.sub_codepage)+"\n") + if (self.film_analizer != None): + config_data.write("film_analizer:"+str(self.film_analizer)+"\n") + if (self.film_player != None): + config_data.write("film_player:"+str(self.film_player)+"\n") + if (self.film_converter != None): + config_data.write("film_converter:"+str(self.film_converter)+"\n") + if (self.menu_converter != None): + config_data.write("menu_converter:"+str(self.menu_converter)+"\n") + config_data.write("subtitle_font_size:"+str(self.subtitles_font_size)+"\n") config_data.close() except: pass + + def append_log(self,data,cr = True): + + self.log+=data + if (cr): + self.log += "\n" + + def clear_log(self): + + self.log = "" + + def get_log(self): + + return self.log \ No newline at end of file diff --git a/src/devede/converter.py b/src/devede/converter.py new file mode 100644 index 0000000..f71a6e3 --- /dev/null +++ b/src/devede/converter.py @@ -0,0 +1,115 @@ +# Copyright 2014 (C) Raster Software Vigo (Sergio Costas) +# +# This file is part of DeVeDe-NG +# +# DeVeDe-NG is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# DeVeDe-NG is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + +import devede.configuration_data +import devede.mpv_converter + +class converter: + + current_converter = None + + @staticmethod + def get_converter(): + if converter.current_converter == None: + converter.current_converter = converter.converter() + return converter.current_converter + + + def __init__(self): + + self.config = devede.configuration_data.configuration.get_config() + self.c = [devede.mpv_converter.mpv_converter] + + self.analizers = {} + self.default_analizer = None + self.players = {} + self.default_player = None + self.converters = {} + self.default_converter = None + self.menuers = {} + self.default_menuer = None + + for element in self.c: + e = element() + if (e.check_is_installed() == False): + continue + name = e.display_name + if (e.supports_analize): + self.analizers[name] = element + if (self.default_analizer == None): + self.default_analizer = element + if (e.supports_play): + self.players[name] = element + if (self.default_player == None): + self.default_player = element + if (e.supports_convert): + self.converters[name] = element + if (self.default_converter == None): + self.default_converter = element + if (e.supports_menu): + self.menuers[name] = element + if (self.default_menuer == None): + self.default_menuer = element + + + def get_needed_programs(self): + """ returns a tupla with four lists. When a list is NONE, there are installed in the system + programs that covers the needs for that group; when not, it contains the programs valid + to cover the needs for that group. + The groups are, in this order: ANALIZERS, PLAYERS, CONVERTERS, MENUERS + (menuers are the programs that creates the mpeg files for menus) + """ + + if (self.default_analizer != None): + analizers = None + else: + analizers = [] + if (self.default_player != None): + players = None + else: + players = [] + if (self.default_converter != None): + converters = None + else: + converters = [] + if (self.default_menuer != None): + menuers = None + else: + menuers = [] + + for element in self.c: + e = element() + name = e.display_name + if (e.supports_analize) and (analizers != None): + analizers.append(name) + if (e.supports_play) and (players != None): + players.append(name) + if (e.supports_convert) and (converters != None): + converters.append(name) + if (e.supports_menu) and (menuers != None): + menuers.append(name) + + return ( analizers, players, converters, menuers ) + + + def get_film_analizer(self): + """ returns a class for the desired film analizer, or the most priviledged if the desired is not installed """ + + if (self.config.film_analizer == None) or (self.analizers.has_key(self.config.film_analizer) == False): + return self.default_analizer + else: + return self.analizers[self.config.film_analizer] diff --git a/src/devede/executor.py b/src/devede/executor.py new file mode 100644 index 0000000..e388f58 --- /dev/null +++ b/src/devede/executor.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +# Copyright 2014 (C) Raster Software Vigo (Sergio Costas) +# +# This file is part of DeVeDe-NG +# +# DeVeDe-NG is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# DeVeDe-NG is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + +import subprocess + +import devede.configuration_data + +class executor: + """ This class encapsulates everything needed for launching processes """ + + def __init__(self): + + self.config = devede.configuration_data.configuration.get_config() + + + \ No newline at end of file diff --git a/src/devede/file_movie.py b/src/devede/file_movie.py index 6b55ab4..54f95e0 100644 --- a/src/devede/file_movie.py +++ b/src/devede/file_movie.py @@ -17,72 +17,149 @@ from gi.repository import Gtk,GObject import os + import devede.configuration_data +import devede.interface_manager +import devede.converter -class file_movie(GObject.GObject): +class file_movie(devede.interface_manager.interface_manager): - counter2 = 0 + __gsignals__ = {'title_changed': (GObject.SIGNAL_RUN_FIRST, None,(str,))} def __init__(self,file_name): GObject.GObject.__init__(self) - self.config = devede.configuration_data.configuration.get_config() - self.file_name = file_name - self.title_name = os.path.splitext(os.path.basename(file_name))[0] - self.wfile_properties = None - self.model = None - self.treeiter = None - self.builder = None - - self.video_rate = 0 - self.audio_rate = 0 - self.final_size = None - self.aspect_ratio = None + devede.interface_manager.interface_manager.__init__(self) - def set_type(self,disc_type = None): + self.wfile_properties = None + self.builder = None + + self.config = devede.configuration_data.configuration.get_config() + self.set_type(None, self.config.disc_type) + self.config.connect('disc_type',self.set_type) + + self.add_text("file_name", file_name) + self.add_text("title_name", os.path.splitext(os.path.basename(file_name))[0]) + self.add_label("original_size",None) + self.add_label("original_length",None) + self.add_label("original_videorate",None) + self.add_label("original_audiorate",None) + self.add_label("original_aspect_ratio",None) + self.add_label("original_fps",None) + + self.add_toggle("show_in_menu", True) + self.add_toggle("format_pal",self.config.PAL) + self.add_toggle("video_rate_automatic", True) + self.add_toggle("audio_rate_automatic", True) + self.add_toggle("divide_in_chapters", True) + self.add_toggle("force_subtitles", False) + self.add_toggle("mirror_horizontal", False) + self.add_toggle("mirror_vertical", False) + self.add_toggle("two_pass_encoding", True) + self.add_toggle("sound5_1", False) + self.add_toggle("copy_sound", False) + self.add_toggle("is_mpeg_ps", False) + self.add_toggle("no_reencode_audio_video", False) + if (self.disc_type == "divx") or (self.disc_type == "mkv"): + self.add_toggle("gop12", False) + else: + self.add_toggle("gop12", True) + + self.add_group("final_size_pal", ["size_auto", "size_1920x1080", "size_1280x720", "size_720x576", "size_704x576", "size_480x576","size_352x576", "size_352x288"], "size_auto") + self.add_group("final_size_ntsc", ["size_auto_ntsc", "size_1920x1080_ntsc", "size_1280x720_ntsc", "size_720x480", "size_704x480", "size_480x480","size_352x480", "size_352x240"], "size_auto_ntsc") + self.add_group("aspect_ratio", ["aspect_auto", "aspect_classic", "aspect_wide"], "aspect_auto") + self.add_group("scaling", ["add_black_bars", "scale_picture" ,"cut_picture"], "add_black_bars") + self.add_group("rotation",["rotation_0","rotation_90","rotation_180","rotation_270"], "rotation_0") + self.add_group("deinterlace", ["deinterlace_none", "deinterlace_ffmpeg", "deinterlace_yadif"], "deinterlace_none") + self.add_group("actions", ["action_stop","action_play_first","action__play_previous","action_play_again","action_play_next","action_play_last"], "action_stop") + + self.add_integer_adjustment("volume", 100) + if (self.disc_type == "dvd"): + self.add_integer_adjustment("video_rate", 5000) + elif (self.disc_type == "vcd"): + self.add_integer_adjustment("video_rate", 1152) + else: + self.add_integer_adjustment("video_rate", 2000) + self.add_integer_adjustment("audio_rate", 224) + self.add_integer_adjustment("subt_font_size", 28) + self.add_float_adjustment("audio_delay", 0.0) + + self.add_show_hide("format_pal", ["size_pal"], ["size_ntsc"]) + + self.add_enable_disable("divide_in_chapters", ["chapter_size_spinbutton"], []) + self.add_enable_disable("video_rate_automatic", [], ["video_spinbutton"]) + self.add_enable_disable("audio_rate_automatic", [], ["audio_spinbutton"]) + self.add_enable_disable("sound5_1", ["copy_sound"], []) + + self.add_enable_disable("copy_sound", [], ["audio_delay_spinbutton","audio_rate_automatic","audio_spinbutton","spinbutton_volume","scale_volume","reset_volume"]) + + common_elements = ["gop12","video_rate_automatic","video_spinbutton","audio_rate_automatic","audio_spinbutton","format_pal","format_ntsc","spinbutton_volume","scale_volume","reset_volume", + "size_auto", "size_1920x1080", "size_1280x720", "size_720x576", "size_704x576", "size_480x576","size_352x576", "size_352x288", + "size_auto_ntsc", "size_1920x1080_ntsc", "size_1280x720_ntsc", "size_720x480", "size_704x480", "size_480x480","size_352x480", "size_352x240", + "aspect_auto","aspect_classic","aspect_wide","mirror_horizontal","mirror_vertical","add_black_bars","scale_picture","cut_picture", + "rotation_0","rotation_90","rotation_180","rotation_270","two_pass_encoding","deinterlace_none","deinterlace_ffmpeg","deinterlace_yadif", + "audio_delay_spinbutton","sound5_1","copy_sound"] + + is_mpeg_ps_list = common_elements[:] + is_mpeg_ps_list.append("no_reencode_audio_video") + is_mpeg_ps_list.append("font_size_spinbutton") + is_mpeg_ps_list.append("force_subtitles") + is_mpeg_ps_list.append("button_add_subtitles") + is_mpeg_ps_list.append("button_del_subtitles") + no_reencode_audio_video_list = common_elements[:] + no_reencode_audio_video_list.append("is_mpeg_ps") + + self.add_enable_disable("is_mpeg_ps", [], is_mpeg_ps_list) + self.add_enable_disable("no_reencode_audio_video", [], no_reencode_audio_video_list) + #self.add_enable_disable("", [], []) + + + + + #cv = devede.converter.converter() + #cv.get_film_data(self) + + def set_type(self,obj = None,disc_type = None): if (disc_type != None): self.disc_type = disc_type - if (disc_type == "dvd"): - self.video_rate = 5000 - self.audio_rate = 224 - self.final_size = "size_auto" - self.aspect_ratio = "aspect_auto" - elif (disc_type == "vcd"): - self.video_rate = 1152 - self.audio_rate = 224 - self.final_size = "size_352x288" - self.aspect_ratio = "aspect_classic" - elif (disc_type == "svcd"): - self.video_rate = 2000 - self.audio_rate = 224 - self.final_size = "size_480x576" - self.aspect_ratio = "aspect_classic" - elif (disc_type == "cvd"): - self.video_rate = 2000 - self.audio_rate = 224 - self.final_size = "size_352x576" - self.aspect_ratio = "aspect_classic" - elif (disc_type == "divx"): - self.video_rate = 5000 - self.audio_rate = 224 - self.final_size = "size_auto" - self.aspect_ratio = "aspect_auto" + + if (disc_type == "vcd"): + self.final_size_auto_width = 352 + self.final_size_auto_height_pal = 288 + self.final_size_auto_height_ntsc = 240 + self.video_rate_auto_value = 1152 + self.audio_rate_auto_value = 224 + elif (disc_type == "svcd"): + self.final_size_auto_width = 480 + self.final_size_auto_height_pal = 576 + self.final_size_auto_height_ntsc = 480 + self.video_rate_auto_value = -1 + self.audio_rate_auto_value = -1 + elif (disc_type == "cvd"): + self.final_size_auto_width = 352 + self.final_size_auto_height_pal = 576 + self.final_size_auto_height_ntsc = 480 + self.video_rate_auto_value = -1 + self.audio_rate_auto_value = -1 + else: # dvd, divx and mkv + self.final_size_auto_width = -1 + self.final_size_auto_height_pal = -1 + self.final_size_auto_height_ntsc = -1 + self.video_rate_auto_value = -1 + self.audio_rate_auto_value = -1 def delete_file(self): print("Deleted file "+self.file_name) - def properties(self,model,treeiter): - + def properties(self): + if (self.wfile_properties != None): self.wfile_properties.present() return - - self.model = model - self.treeiter = treeiter - + self.builder = Gtk.Builder() self.builder.set_translation_domain(self.config.gettext_domain) @@ -90,25 +167,89 @@ class file_movie(GObject.GObject): self.builder.connect_signals(self) self.wfile_properties = self.builder.get_object("file_properties") self.wfile_properties.show_all() - - self.wfile = self.builder.get_object("label_filename") - self.wtitle = self.builder.get_object("entry_title") - - self.wfile.set_text(self.file_name) - self.wtitle.set_text(self.title_name) - + + self.wshow_in_menu = self.builder.get_object("show_in_menu") + + self.wnotebook = self.builder.get_object("notebook") + + # elements in page GENERAL + self.wframe_video_rate = self.builder.get_object("frame_video_rate") + self.wframe_audio_rate = self.builder.get_object("frame_audio_rate") + self.wframe_division_chapters = self.builder.get_object("frame_division_chapters") + + # elements in page VIDEO OPTIONS + self.wsize_1920x1080 = self.builder.get_object("size_1920x1080") + self.wsize_1280x720 = self.builder.get_object("size_1280x720") + self.wsize_1920x1080_ntsc = self.builder.get_object("size_1920x1080_ntsc") + self.wsize_1280x720_ntsc = self.builder.get_object("size_1280x720_ntsc") + self.wframe_final_size = self.builder.get_object("frame_final_size") + self.wframe_aspect_ratio = self.builder.get_object("frame_aspect_ratio") + + # elements in page AUDIO + self.wsound5_1 = self.builder.get_object("sound5_1") + self.wcopy_sound = self.builder.get_object("copy_sound") + + # Adjust the interface UI to the kind of disc + + if (self.disc_type == 'dvd'): + self.wsize_1920x1080.hide() + self.wsize_1280x720.hide() + self.wsize_1920x1080_ntsc.hide() + self.wsize_1280x720_ntsc.hide() + elif (self.disc_type == 'vcd'): + self.wshow_in_menu.hide() + self.wframe_video_rate.hide() + self.wframe_audio_rate.hide() + self.wframe_division_chapters.hide() + self.wframe_final_size.hide() + self.wframe_aspect_ratio.hide() + self.wsound5_1.hide() + self.wcopy_sound.hide() + self.wnotebook.remove_page(5) + elif (self.disc_type == 'svcd'): + self.wsize_1920x1080.hide() + self.wsize_1280x720.hide() + self.wsize_1920x1080_ntsc.hide() + self.wsize_1280x720_ntsc.hide() + self.wshow_in_menu.hide() + self.wframe_division_chapters.hide() + self.wframe_aspect_ratio.hide() + self.wsound5_1.hide() + self.wcopy_sound.hide() + self.wnotebook.remove_page(5) + elif (self.disc_type == 'cvd'): + self.wsize_1920x1080.hide() + self.wsize_1280x720.hide() + self.wsize_1920x1080_ntsc.hide() + self.wsize_1280x720_ntsc.hide() + self.wshow_in_menu.hide() + self.wframe_division_chapters.hide() + self.wframe_aspect_ratio.hide() + self.wsound5_1.hide() + self.wcopy_sound.hide() + self.wnotebook.remove_page(5) + elif (self.disc_type == 'divx'): + self.wshow_in_menu.hide() + self.wframe_division_chapters.hide() + self.wsound5_1.hide() + self.wcopy_sound.hide() + self.wnotebook.remove_page(5) + self.wnotebook.remove_page(1) + elif (self.disc_type == 'mkv'): + self.wshow_in_menu.hide() + self.wframe_division_chapters.hide() + self.wnotebook.remove_page(5) + + self.update_ui(self.builder) + def on_button_accept_clicked(self,b): - self.title_name = self.wtitle.get_text() - self.model.set_value(self.treeiter,1,self.title_name) + self.store_ui(self.builder) + self.emit('title_changed',self.title_name) self.on_button_cancel_clicked(None) - + def on_button_cancel_clicked(self,b): - + self.wfile_properties.destroy() self.wfile_properties = None self.builder = None - self.model = None - self.treeiter = None - - \ No newline at end of file diff --git a/src/devede/interface_manager.py b/src/devede/interface_manager.py new file mode 100644 index 0000000..986ecd7 --- /dev/null +++ b/src/devede/interface_manager.py @@ -0,0 +1,266 @@ +# Copyright 2014 (C) Raster Software Vigo (Sergio Costas) +# +# This file is part of DeVeDe-NG +# +# DeVeDe-NG is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# DeVeDe-NG is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + +from gi.repository import GObject + +class interface_manager(GObject.GObject): + """ This class allows to automatically generate variables for a GLADE interface, + set the widgets in the interface to their values, and copy the current values + in the widgets to the variables """ + + def __init__(self): + + self.groups = {} + self.toggles = [] + self.labels = [] + self.text = [] + self.show_hide = [] + self.enable_disable = [] + self.float_adjustments = [] + self.integer_adjustments = [] + + def add_group(self,group_name,radiobutton_list,default_value): + """ Adds a group of radiobuttons and creates an internal variable with + the name group_name, setting it to default_value. The + value for the variable will be the name of the active + radiobutton """ + + if (default_value != None): + exec('self.'+group_name+' = "'+str(default_value)+'"') + else: + exec('self.'+group_name+' = None') + self.groups[group_name] = radiobutton_list + + def add_toggle(self,toggle_name,default_value): + """ Adds an internal variable with the name toggle_name, linked to a widget + element with the same name (must be or inherint from Gtk.ToogleButton). + The default value can be True of False """ + + exec('self.'+toggle_name+' = '+str(default_value)) + self.toggles.append(toggle_name) + + def add_text(self,text_name,default_value): + """ Adds an internal variable with the name text_name, linked to an + element with the same name (must be a Gtk.TextEntry or a Gtk.Label). + The default value can be a text or None """ + + if (default_value != None): + exec('self.'+text_name+' = "'+str(default_value)+'"') + else: + exec('self.'+text_name+' = None') + self.text.append(text_name) + + def add_label(self,text_name,default_value): + """ Adds an internal variable with the name text_name, linked to an + element with the same name (must be a Gtk.TextEntry or a Gtk.Label). + The default value can be a text or None. This element is copied to the UI, + but is never updated from the UI if the user changes it """ + + exec('self.'+text_name+' = default_value') + self.labels.append(text_name) + + def add_integer_adjustment(self,adjustment_name,default_value): + """ Adds an internal variable with the name text_name, linked to an + element with the same name (must be a Gtk.Adjustment). + The default value must be an integer """ + + exec('self.'+adjustment_name+' = '+str(default_value)) + self.integer_adjustments.append(adjustment_name) + + def add_float_adjustment(self,adjustment_name,default_value): + """ Adds an internal variable with the name text_name, linked to an + element with the same name (must be a Gtk.Adjustment). + The default value must be an float """ + + exec('self.'+adjustment_name+' = '+str(default_value)) + self.float_adjustments.append(adjustment_name) + + + def add_show_hide(self,element_name,to_show,to_hide): + """ Adds an element that can be active or inactive, and two lists of elements. + The first one contains elements that will be visible when the element is + active, and invisible when it is inactive, and the second one contains + elements that will be visible when the element is inactive, and + invisible when the element is active """ + + self.show_hide.append([element_name, to_show, to_hide]) + + def add_enable_disable(self,element_name,to_enable,to_disable): + """ Adds an element that can be active or inactive, and two lists of elements. + The first one contains elements that will be enabled when the element is + active, and disabled when it is inactive, and the second one contains + elements that will be enabled when the element is inactive, and + disabled when the element is active """ + + self.enable_disable.append([element_name, to_enable, to_disable]) + + def update_ui(self,builder): + """ Sets the value of the widgets in base of the internal variables """ + + for key in self.groups: + obj = eval('self.'+key) + builder.get_object(obj).set_active(True) + + for element in self.toggles: + value = eval('self.'+element) + builder.get_object(element).set_active(value) + + for element in self.text: + value = eval('self.'+element) + if (value != None): + builder.get_object(element).set_text(value) + else: + builder.get_object(element).set_text("") + + for element in self.labels: + value = eval('self.'+element) + if (value != None): + builder.get_object(element).set_text(str(value)) + else: + builder.get_object(element).set_text("") + + for element in self.integer_adjustments: + value = eval('self.'+element) + builder.get_object(element).set_value(float(value)) + + for element in self.float_adjustments: + value = eval('self.'+element) + builder.get_object(element).set_value(value) + + self.show_hide_obj = {} + for element in self.show_hide: + obj = builder.get_object(element[0]) + to_show = [] + for e2 in element[1]: + to_show.append(builder.get_object(e2)) + to_hide = [] + for e3 in element[2]: + to_hide.append(builder.get_object(e3)) + self.show_hide_obj[obj] = [to_show, to_hide] + obj.connect('toggled',self.toggled_element) + self.toggled_element(obj) + + self.enable_disable_obj = {} + for element in self.enable_disable: + obj = builder.get_object(element[0]) + to_enable = [] + for e2 in element[1]: + to_enable.append(builder.get_object(e2)) + to_disable = [] + for e3 in element[2]: + to_disable.append(builder.get_object(e3)) + self.enable_disable_obj[obj] = [to_enable, to_disable] + obj.connect('toggled',self.toggled_element2) + self.toggled_element2(obj) + + def toggled_element(self,element): + """ Wenever an element with 'hide' or 'show' needs is toggled, this callback is called """ + + # First, show all items for each possible element + for key in self.show_hide_obj: + to_show = self.show_hide_obj[key][0] + to_hide = self.show_hide_obj[key][1] + + active = key.get_active() + + for item in to_show: + if active: + item.show() + + for item in to_hide: + if not active: + item.show() + + # And now, hide all items that must be hiden + # This is done this way because this allows to have an item being hiden by + # one widget, and being shown by another: in that case, it will be hiden always + for key in self.show_hide_obj: + to_show = self.show_hide_obj[key][0] + to_hide = self.show_hide_obj[key][1] + + active = key.get_active() + + for item in to_show: + if not active: + item.hide() + + for item in to_hide: + if active: + item.hide() + + + def toggled_element2(self,element): + """ Wenever an element with 'enable' or 'disable' needs is toggled, this callback is called """ + + # First enable all items that must be enabled + for key in self.enable_disable_obj: + to_enable = self.enable_disable_obj[key][0] + to_disable = self.enable_disable_obj[key][1] + + active = key.get_active() + if (active): + for item in to_enable: + item.set_sensitive(True) + else: + for item in to_disable: + item.set_sensitive(True) + + # And now, disable all items that must be disabled + # This is done this way because this allows to have an item being disabled by + # one widget, and being enabled by another: in that case, it will be disabled always + for key in self.enable_disable_obj: + to_enable = self.enable_disable_obj[key][0] + to_disable = self.enable_disable_obj[key][1] + + active = key.get_active() + if (not active): + for item in to_enable: + item.set_sensitive(False) + else: + for item in to_disable: + item.set_sensitive(False) + + def store_ui(self,builder): + """ Takes the values of the widgets and stores them in the internal variables """ + + for key in self.groups: + for element in self.groups[key]: + obj = builder.get_object(element) + if obj.get_active(): + exec('self.'+key+' = "'+element+'"') + break + + for element in self.toggles: + obj = builder.get_object(element) + if obj.get_active(): + exec('self.'+element+' = True') + else: + exec('self.'+element+' = False') + + for element in self.text: + obj = builder.get_object(element) + exec('self.'+element+' = obj.get_text()') + + for element in self.integer_adjustments: + obj = builder.get_object(element) + exec('self.'+element+' = int(obj.get_value())') + + for element in self.float_adjustments: + obj = builder.get_object(element) + exec('self.'+element+' = obj.get_value()') + + \ No newline at end of file diff --git a/src/devede/mpv_converter.py b/src/devede/mpv_converter.py new file mode 100644 index 0000000..f132104 --- /dev/null +++ b/src/devede/mpv_converter.py @@ -0,0 +1,105 @@ +# Copyright 2014 (C) Raster Software Vigo (Sergio Costas) +# +# This file is part of DeVeDe-NG +# +# DeVeDe-NG is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# DeVeDe-NG is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + +import subprocess +import devede.configuration_data + +class mpv_converter: + + def __init__(self): + + self.config = devede.configuration_data.configuration.get_config() + self.supports_analize = True + self.supports_play = True + self.supports_convert = False + self.supports_menu = False + self.display_name = "MPV" + + def check_is_installed(self): + handle = subprocess.Popen(["mpv","-v"]) + if 0==handle.wait(): + return True + else: + return False + + def get_film_data(self,movie): + """ processes a file, refered by the FILE_MOVIE movie object, and fills its + main data (resolution, FPS, length...) """ + + def get_film_data2(self,movie,check_audio): + + if (check_audio): + frames = "0" + else: + frames = "1" + + if self.config.mpv_available: + command_line = ["mpv","identify","-loop","1","-identify", "-ao", "null", "-vo", "null", "-frames", "1"] + else: + command_line = ["mplayer","identify","-loop","1","-identify", "-ao", "null", "-vo", "null", "-frames", "1"] + + command_line.append(movie.file_name) + + handle = subprocess.Popen(command_line) + (stdout, stderr) = handle.communicate() + + minimum_audio=-1 + audio_list=[] + audio = 0 + video = 0 + + for line in stdout: + line=self.remove_ansi(line) + if line == "": + continue + position=line.find("ID_") + if position==-1: + continue + line=line[position:] + if line[:16]=="ID_VIDEO_BITRATE": + vrate=int(line[17:]) + if line[:14]=="ID_VIDEO_WIDTH": + width=int(line[15:]) + if line[:15]=="ID_VIDEO_HEIGHT": + height=int(line[16:]) + if line[:15]=="ID_VIDEO_ASPECT": + aspect_ratio=float(line[16:]) + if line[:12]=="ID_VIDEO_FPS": + fps2=line[13:] + while ord(fps2[-1])<32: + fps2=fps2[:-1] + posic=line.find(".") + if posic==-1: + fps=int(line[13:]) + else: + fps=int(line[13:posic]) + if line[posic+1]=="9": + fps+=1 + if line[:16]=="ID_AUDIO_BITRATE": + arate=int(line[17:]) + if line[:13]=="ID_AUDIO_RATE": + audiorate=int(line[14:]) + if line[:9]=="ID_LENGTH": + length=int(float(line[10:])) + if line[:11]=="ID_VIDEO_ID": + video+=1 + if line[:11]=="ID_AUDIO_ID": + audio+=1 + audio_track=int(line[12:]) + if (minimum_audio == -1) or (minimum_audio>audio_track): + minimum_audio=audio_track + audio_list.append(audio_track) \ No newline at end of file diff --git a/src/devede/project.py b/src/devede/project.py index 1634c44..ce8ce33 100644 --- a/src/devede/project.py +++ b/src/devede/project.py @@ -27,83 +27,62 @@ class devede_project: def __init__(self): self.config = devede.configuration_data.configuration.get_config() - self.destroy_all() + self.disc_type = self.config.disc_type - def destroy_all(self): - - self.wask_window = None - self.wmain_window = None - self.wdisc_size = None - self.wliststore_files = None - self.wfiles = None - self.wdisc_fill_level = None - self.wuse_pal = None - self.wuse_ntsc = None - self.wcreate_menu = None - self.disc_type = None - self.wadd_file = None - self.wdelete_file = None - self.wup_file = None - self.wdown_file = None - self.wproperties_file = None - self.wcreate_disc = None - - - def ask_type(self): - """ This method resets the project and asks the user what kind of project want to do """ - - if (self.wask_window != None): - self.wask_window.present() - return + self.current_title = None builder = Gtk.Builder() builder.set_translation_domain(self.config.gettext_domain) - builder.add_from_file(os.path.join(self.config.glade,"wselect_disk.ui")) + builder.add_from_file(os.path.join(self.config.glade,"wmain.ui")) builder.connect_signals(self) - self.wask_window = builder.get_object("wselect_disk") - self.wask_window.show_all() - def on_wselect_disk_delete_event(self,w,e): - Gtk.main_quit() - return False + # Interface widgets + self.wmain_window = builder.get_object("wmain_window") + self.wdisc_size = builder.get_object("disc_size") + self.wliststore_files = builder.get_object("liststore_files") + self.wfiles = builder.get_object("files") + self.wdisc_fill_level = builder.get_object("disc_fill_level") + self.wuse_pal = builder.get_object("use_pal") + self.wuse_ntsc = builder.get_object("use_ntsc") + self.wcreate_menu = builder.get_object("create_menu") + self.wframe_titles = builder.get_object("frame_titles") - def on_button_dvd_clicked(self,b): + self.wadd_file = builder.get_object("add_file") + self.wdelete_file = builder.get_object("delete_file") + self.wup_file = builder.get_object("up_file") + self.wdown_file = builder.get_object("down_file") + self.wproperties_file = builder.get_object("properties_file") + self.wpreview_file = builder.get_object("preview_file") - self.set_type("dvd") + self.wcreate_disc = builder.get_object("create_disc") - def on_button_vcd_clicked(self,b): + selection = self.wfiles.get_selection() + selection.mode = Gtk.SelectionMode.SINGLE - self.set_type("vcd") + if (self.config.PAL): + self.wuse_pal.set_active(True) + else: + self.wuse_ntsc.set_active(True) - def on_button_svcd_clicked(self,b): - - self.set_type("svcd") - - def on_button_cvd_clicked(self,b): - - self.set_type("cvd") - - def on_button_divx_clicked(self,b): - - self.set_type("divx") + self.config.connect('disc_type',self.set_type) + if (self.disc_type != None): + self.set_type(None, self.disc_type) - def set_type(self,disc_type): + def set_type(self,obj=None,disc_type=None): """ this method sets the disk type to the specified one and adapts the interface in the main window to it. Also leaves everything ready to start creating a new disc """ - if (self.wask_window != None): - self.wask_window.destroy() - self.destroy_all() - - self.disc_type = disc_type - self.show_main_window() + if (disc_type != None): + self.disc_type = disc_type + self.wmain_window.show_all() + self.set_interface_status(None) # Set the default disc size - if (self.disc_type == "dvd"): + if (self.disc_type == "dvd") or (self.disc_type == "mkv"): self.wdisc_size.set_active(1) # 4.7 GB DVD else: self.wdisc_size.set_active(3) # 700 MB CD @@ -156,52 +135,8 @@ class devede_project: self.wdown_file.set_sensitive(False) - def show_main_window(self): - - if (self.wmain_window != None): - self.wmain_window.present() - return - - self.current_title = None - - builder = Gtk.Builder() - builder.set_translation_domain(self.config.gettext_domain) - - builder.add_from_file(os.path.join(self.config.glade,"wmain.ui")) - builder.connect_signals(self) - - # Interface widgets - self.wmain_window = builder.get_object("wmain_window") - self.wdisc_size = builder.get_object("disc_size") - self.wliststore_files = builder.get_object("liststore_files") - self.wfiles = builder.get_object("files") - self.wdisc_fill_level = builder.get_object("disc_fill_level") - self.wuse_pal = builder.get_object("use_pal") - self.wuse_ntsc = builder.get_object("use_ntsc") - self.wcreate_menu = builder.get_object("create_menu") - self.wframe_titles = builder.get_object("frame_titles") - - self.wadd_file = builder.get_object("add_file") - self.wdelete_file = builder.get_object("delete_file") - self.wup_file = builder.get_object("up_file") - self.wdown_file = builder.get_object("down_file") - self.wproperties_file = builder.get_object("properties_file") - self.wpreview_file = builder.get_object("preview_file") - - self.wcreate_disc = builder.get_object("create_disc") - - selection = self.wfiles.get_selection() - selection.mode = Gtk.SelectionMode.SINGLE - - if (self.config.PAL): - self.wuse_pal.set_active(True) - else: - self.wuse_ntsc.set_active(True) - self.wmain_window.show_all() - self.set_interface_status(None) - def on_use_pal_toggled(self,b): - + self.config.PAL = self.wuse_pal.get_active() def on_wmain_window_delete_event(self,b,e=None): @@ -211,14 +146,21 @@ class devede_project: Gtk.main_quit() return True + def title_changed(self,obj,new_title): + + for item in self.wliststore_files: + element = item.model[item.iter][0] + if element == obj: + item.model.set_value(item.iter,1,new_title) + + def on_add_file_clicked(self,b): ask_files = devede.add_files.add_files() - ask_files.set_type(self.disc_type) if (ask_files.run()): for efile in ask_files.files: new_file = devede.file_movie.file_movie(efile) - new_file.set_type(self.disc_type) + new_file.connect('title_changed',self.title_changed) self.wliststore_files.append([new_file, new_file.title_name]) self.set_interface_status(None) @@ -259,8 +201,7 @@ class devede_project: (element, position, model, treeiter) = self.get_current_file() if (element == None): return - - element.properties(model,treeiter) + element.properties() def on_adjust_disc_usage_clicked(self,b): diff --git a/src/devede_ng.py b/src/devede_ng.py index 9af26e1..bbd0309 100755 --- a/src/devede_ng.py +++ b/src/devede_ng.py @@ -24,10 +24,11 @@ from gi.repository import Gtk import devede.project import devede.configuration_data +import devede.choose_disc_type config_data = devede.configuration_data.configuration.get_config() -if config_data.error: +if config_data == None: print ("Can't locate extra files. Aborting.") sys.exit(1) @@ -44,6 +45,6 @@ _ = gettext.gettext Gtk.init(sys.argv) mwindow = devede.project.devede_project() -mwindow.ask_type() +ask_type = devede.choose_disc_type.choose_disc_type() Gtk.main() config_data.save_config()