diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..0e40fe8f --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ + +# Default ignored files +/workspace.xml \ No newline at end of file diff --git a/.idea/freeseer.iml b/.idea/freeseer.iml new file mode 100644 index 00000000..67116063 --- /dev/null +++ b/.idea/freeseer.iml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 00000000..105ce2da --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..a2e120dc --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..6a827896 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..94a25f7f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py index 1b01c570..e3f251ab 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -43,8 +43,8 @@ master_doc = 'index' # General information about the project. -project = u'Freeseer' -copyright = u'© 2011-2014 Free and Open Source Software Learning Centre' +project = 'Freeseer' +copyright = '© 2011-2014 Free and Open Source Software Learning Centre' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -182,8 +182,8 @@ latex_documents = [( 'index', # source start file 'Freeseer.tex', # target name - u'Freeseer Documentation', # title - u'Free and Open Source Software Learning Centre', # author + 'Freeseer Documentation', # title + 'Free and Open Source Software Learning Centre', # author 'manual' # documentclass [howto/manual] )] @@ -216,6 +216,6 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'freeseer', u'Freeseer Documentation', - [u'Free and Open Source Software Learning Centre'], 1) + ('index', 'freeseer', 'Freeseer Documentation', + ['Free and Open Source Software Learning Centre'], 1) ] diff --git a/src/freeseer/framework/config/core.py b/src/freeseer/framework/config/core.py index 8ccdafff..83e5efd5 100644 --- a/src/freeseer/framework/config/core.py +++ b/src/freeseer/framework/config/core.py @@ -31,11 +31,9 @@ from freeseer.framework.config.exceptions import StorageNotSetError -class Option(object): +class Option(object, metaclass=abc.ABCMeta): """Represents a Config option.""" - __metaclass__ = abc.ABCMeta - class NotSpecified(object): pass @@ -98,7 +96,7 @@ def __new__(meta, name, bases, class_attributes): class_attributes, options = meta.find_options(class_attributes) class_attributes['options'] = options cls = super(ConfigBase, meta).__new__(meta, name, bases, class_attributes) - for opt_name, option in options.iteritems(): + for opt_name, option in options.items(): opt_get = functools.partial(cls.get_value, name=opt_name, option=option, presentation=True) opt_set = functools.partial(cls._set_value, name=opt_name, option=option) setattr(cls, opt_name, property(opt_get, opt_set)) @@ -118,7 +116,7 @@ def find_options(class_attributes): return new_attributes, options -class Config(object): +class Config(object, metaclass=ConfigBase): """Base class for all custom configs. To be useful, its body must contain some number of Option instances. @@ -128,8 +126,6 @@ class MyConfig(Config): test = StringOption('default_value') """ - __metaclass__ = ConfigBase - def __init__(self, storage=None, storage_args=None): """ Params: @@ -149,7 +145,7 @@ def _set_value(self, value, name, option): def set_defaults(self): """Sets the values of all options to their default value (if applicable).""" - for name, option in self.options.iteritems(): + for name, option in self.options.items(): if not option.is_required(): self.set_value(name, option, option.default) @@ -210,7 +206,7 @@ def schema(cls): 'properties': {}, } - for name, instance in cls.options.iteritems(): + for name, instance in cls.options.items(): schema['properties'][name] = instance.schema() if instance.is_required(): required.append(name) @@ -221,11 +217,9 @@ def schema(cls): return schema -class ConfigStorage(object): +class ConfigStorage(object, metaclass=abc.ABCMeta): """Defines an interface for loading and storing Config instances.""" - __metaclass__ = abc.ABCMeta - def __init__(self, filepath): """ Params: diff --git a/src/freeseer/framework/config/persist/configparser.py b/src/freeseer/framework/config/persist/configparser.py index 2c47b015..a06144cb 100644 --- a/src/freeseer/framework/config/persist/configparser.py +++ b/src/freeseer/framework/config/persist/configparser.py @@ -22,7 +22,7 @@ # For support, questions, suggestions or any other inquiries, visit: # http://wiki.github.com/Freeseer/freeseer/ -import ConfigParser +from . import ConfigParser from freeseer.framework.config.core import ConfigStorage @@ -34,7 +34,7 @@ def load(self, config_instance, section): parser = ConfigParser.ConfigParser() parser.read([self._filepath]) - for name, option in config_instance.options.iteritems(): + for name, option in config_instance.options.items(): if parser.has_option(section, name): raw = parser.get(section, name) clean = option.decode(raw) @@ -49,7 +49,7 @@ def store(self, config_instance, section): if not parser.has_section(section): parser.add_section(section) - for name, option in config_instance.options.iteritems(): + for name, option in config_instance.options.items(): raw = config_instance.get_value(name, option) clean = option.encode(raw) parser.set(section, name, clean) diff --git a/src/freeseer/framework/config/persist/jsonstorage.py b/src/freeseer/framework/config/persist/jsonstorage.py index 32d88399..636c45ff 100644 --- a/src/freeseer/framework/config/persist/jsonstorage.py +++ b/src/freeseer/framework/config/persist/jsonstorage.py @@ -49,7 +49,7 @@ def load(self, config_instance, section): if section not in dict_: return config_instance - for name, option in config_instance.options.iteritems(): + for name, option in config_instance.options.items(): if name in dict_[section]: raw = dict_[section][name] clean = option.decode(raw) @@ -61,7 +61,7 @@ def store(self, config_instance, section): if section not in dict_: dict_[section] = {} - for name, option in config_instance.options.iteritems(): + for name, option in config_instance.options.items(): raw = config_instance.get_value(name, option) clean = option.encode(raw) dict_[section][name] = clean diff --git a/src/freeseer/framework/config/profile.py b/src/freeseer/framework/config/profile.py index 5f417ee6..6fbc0a6e 100644 --- a/src/freeseer/framework/config/profile.py +++ b/src/freeseer/framework/config/profile.py @@ -153,7 +153,7 @@ def get_storage(self, name): It will also be cached for future invocations of this method. """ if name not in self._storages: - for suffix, engine in self.STORAGE_MAP.iteritems(): + for suffix, engine in self.STORAGE_MAP.items(): if name.endswith(suffix): self._storages[name] = engine(self.get_filepath(name)) break diff --git a/src/freeseer/framework/database.py b/src/freeseer/framework/database.py index c4c9b3f3..1efeb4a4 100644 --- a/src/freeseer/framework/database.py +++ b/src/freeseer/framework/database.py @@ -239,16 +239,16 @@ def get_talks_by_room_and_time(self, room): def get_presentation(self, talk_id): """Returns a Presentation object associated to a talk_id""" result = QtSql.QSqlQuery('''SELECT * FROM presentations WHERE Id="%s"''' % talk_id) - if result.next(): - return Presentation(title=unicode(result.value(1).toString()), - speaker=unicode(result.value(2).toString()), - description=unicode(result.value(3).toString()), - category=unicode(result.value(4).toString()), - event=unicode(result.value(5).toString()), - room=unicode(result.value(6).toString()), - date=unicode(result.value(7).toString()), - startTime=unicode(result.value(8).toString()), - endTime=unicode(result.value(9).toString())) + if next(result): + return Presentation(title=str(result.value(1).toString()), + speaker=str(result.value(2).toString()), + description=str(result.value(3).toString()), + category=str(result.value(4).toString()), + event=str(result.value(5).toString()), + room=str(result.value(6).toString()), + date=str(result.value(7).toString()), + startTime=str(result.value(8).toString()), + endTime=str(result.value(9).toString())) else: return None @@ -256,16 +256,16 @@ def get_string_list(self, column): """Returns a column as a QStringList""" tempList = QStringList() result = QtSql.QSqlQuery('''SELECT DISTINCT %s FROM presentations''' % column) - while result.next(): + while next(result): tempList.append(result.value(0).toString()) return tempList def presentation_exists(self, presentation): """Checks if there's a presentation with the same Speaker and Title already stored""" result = QtSql.QSqlQuery('''SELECT * FROM presentations''') - while result.next(): - if (unicode(presentation.title) == unicode(result.value(1).toString()) - and unicode(presentation.speaker) == unicode(result.value(2).toString())): + while next(result): + if (str(presentation.title) == str(result.value(1).toString()) + and str(presentation.speaker) == str(result.value(2).toString())): return True return False @@ -374,7 +374,7 @@ def get_talk_between_time(self, event, room, startTime, endTime): WHERE Event='%s' AND Room='%s' \ AND Date BETWEEN '%s' \ AND '%s' ORDER BY Date ASC" % (event, room, startTime, endTime)) - query.next() + next(query) if query.isValid(): return query.value(0) else: @@ -458,17 +458,17 @@ def export_talks_to_csv(self, fname): writer.writerow(headers) result = self.get_talks() - while result.next(): - log.debug(unicode(result.value(1).toString())) - writer.writerow({'Title': unicode(result.value(1).toString()), - 'Speaker': unicode(result.value(2).toString()), - 'Abstract': unicode(result.value(3).toString()), - 'Category': unicode(result.value(4).toString()), - 'Event': unicode(result.value(5).toString()), - 'Room': unicode(result.value(6).toString()), - 'Date': unicode(result.value(7).toString()), - 'StartTime': unicode(result.value(8).toString()), - 'EndTime': unicode(result.value(9).toString())}) + while next(result): + log.debug(str(result.value(1).toString())) + writer.writerow({'Title': str(result.value(1).toString()), + 'Speaker': str(result.value(2).toString()), + 'Abstract': str(result.value(3).toString()), + 'Category': str(result.value(4).toString()), + 'Event': str(result.value(5).toString()), + 'Room': str(result.value(6).toString()), + 'Date': str(result.value(7).toString()), + 'StartTime': str(result.value(8).toString()), + 'EndTime': str(result.value(9).toString())}) finally: file.close() @@ -520,10 +520,10 @@ def clear_report_db(self): def get_report(self, talkid): """Returns a failure from a given talkid. Returned value is a Failure object""" result = QtSql.QSqlQuery('''SELECT * FROM failures WHERE Id = "%s"''' % talkid) - if result.next(): - failure = Failure(unicode(result.value(0).toString()), # id - unicode(result.value(1).toString()), # comment - unicode(result.value(2).toString()), # indicator + if next(result): + failure = Failure(str(result.value(0).toString()), # id + str(result.value(1).toString()), # comment + str(result.value(2).toString()), # indicator result.value(3).toBool()) # release else: failure = None @@ -533,10 +533,10 @@ def get_reports(self): """Returns a list of failures in Report format""" result = QtSql.QSqlQuery('''Select * FROM failures''') list = [] - while result.next(): - failure = Failure(unicode(result.value(0).toString()), # id - unicode(result.value(1).toString()), # comment - unicode(result.value(2).toString()), # indicator + while next(result): + failure = Failure(str(result.value(0).toString()), # id + str(result.value(1).toString()), # comment + str(result.value(2).toString()), # indicator bool(result.value(3))) # release p = self.get_presentation(failure.talkId) r = Report(p, failure) diff --git a/src/freeseer/framework/qt_key_grabber.py b/src/freeseer/framework/qt_key_grabber.py index b08e990e..e55f71f7 100644 --- a/src/freeseer/framework/qt_key_grabber.py +++ b/src/freeseer/framework/qt_key_grabber.py @@ -48,22 +48,22 @@ def __init__(self, parent=None): def keyPressEvent(self, event): other = None if event.key() == QtCore.Qt.Key_Shift: - self.modifiers[QtCore.Qt.Key_Shift] = u'Shift' + self.modifiers[QtCore.Qt.Key_Shift] = 'Shift' elif event.key() == QtCore.Qt.Key_Control: - self.modifiers[QtCore.Qt.Key_Control] = u'Ctrl' + self.modifiers[QtCore.Qt.Key_Control] = 'Ctrl' elif event.key() == QtCore.Qt.Key_Alt: - self.modifiers[QtCore.Qt.Key_Alt] = u'Alt' + self.modifiers[QtCore.Qt.Key_Alt] = 'Alt' elif event.key() == QtCore.Qt.Key_Meta: - self.modifiers[QtCore.Qt.Key_Meta] = u'Meta' + self.modifiers[QtCore.Qt.Key_Meta] = 'Meta' else: other = event.text() if other: if QtCore.Qt.Key_Control in self.modifiers: - self.key_string = u'+'.join(self.modifiers.values() + [unicode(chr(event.key()))]) + self.key_string = '+'.join(list(self.modifiers.values()) + [str(chr(event.key()))]) else: - self.key_string = u'+'.join(self.modifiers.values() + [unicode(other)]) + self.key_string = '+'.join(list(self.modifiers.values()) + [str(other)]) else: - self.key_string = u'+'.join(self.modifiers.values()) + self.key_string = '+'.join(list(self.modifiers.values())) if (self.parent.core.config.key_rec == 'Ctrl+Shift+R'): self.flag = True diff --git a/src/freeseer/framework/util.py b/src/freeseer/framework/util.py index 40e43f68..e793ae3a 100644 --- a/src/freeseer/framework/util.py +++ b/src/freeseer/framework/util.py @@ -90,7 +90,7 @@ def make_record_name(presentation): make_shortname(presentation.speaker), make_shortname(presentation.title), ] - record_name = unicode('-'.join(tag for tag in tags if tag)) + record_name = str('-'.join(tag for tag in tags if tag)) # Convert unicode filenames to their equivalent ascii so that # we don't run into issues with gstreamer or filesystems. @@ -121,7 +121,7 @@ def reset(configdir): if confirm_yes() is True: shutil.rmtree(configdir) else: - print("%s is not a invalid configuration directory." % configdir) + print(("%s is not a invalid configuration directory." % configdir)) def reset_configuration(configdir, profile='default'): @@ -139,7 +139,7 @@ def reset_configuration(configdir, profile='default'): if os.path.exists(plugin_conf): os.remove(plugin_conf) else: - print("%s is not a invalid configuration directory." % configdir) + print(("%s is not a invalid configuration directory." % configdir)) def reset_database(configdir, profile='default'): @@ -153,7 +153,7 @@ def reset_database(configdir, profile='default'): if os.path.exists(dbfile): os.remove(dbfile) else: - print("%s is not a invalid configuration directory." % configdir) + print(("%s is not a invalid configuration directory." % configdir)) def validate_configdir(configdir): @@ -168,7 +168,7 @@ def validate_configdir(configdir): def confirm_yes(): """Prompts the user to confirm by typing 'yes' in response""" - confirm = raw_input("Enter 'yes' to confirm: ") + confirm = input("Enter 'yes' to confirm: ") if confirm == 'yes': return True return False diff --git a/src/freeseer/framework/util.py.bak b/src/freeseer/framework/util.py.bak new file mode 100644 index 00000000..40e43f68 --- /dev/null +++ b/src/freeseer/framework/util.py.bak @@ -0,0 +1,174 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# freeseer - vga/presentation capture software +# +# Copyright (C) 2013, 2014 Free and Open Source Software Learning Centre +# http://fosslc.org +# +# This program 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. +# +# This program 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 . + +# For support, questions, suggestions or any other inquiries, visit: +# http://wiki.github.com/Freeseer/freeseer/ + +import ctypes +import os +import shutil +import sys +import unicodedata + + +def format_size(num): + for x in ['bytes', 'KB', 'MB', 'GB', 'TB']: + if num < 1024.0: + return "%3.1f %s" % (num, x) + num /= 1024.0 + + +def get_free_space(directory): + """ Return directory free space (in human readable form) """ + if sys.platform in ["win32", "cygwin"]: + free_bytes = ctypes.c_ulonglong(0) + ctypes.windll.kernel32.GetDiskFreeSpaceExW(ctypes.c_wchar_p(directory), + None, None, ctypes.pointer(free_bytes)) + space = free_bytes.value + else: + space = os.statvfs(directory).f_bfree * os.statvfs(directory).f_frsize + + return format_size(space) + +### +### Filename related functions +### + + +def get_record_name(extension, presentation=None, filename=None, path="."): + """Returns the filename to use when recording. + + If a record name with a .None extension is returned, the record name + will just be ignored by the output plugin (e.g. Video Preview plugin). + + Function will return None if neither presentation nor filename is passed. + """ + if presentation is not None: + recordname = make_record_name(presentation) + elif filename is not None: + recordname = filename + else: + return None + + count = 0 + tempname = recordname + + # Add a number to the end of a duplicate record name so we don't + # overwrite existing files + while(os.path.exists(os.path.join(path, "%s.%s" % (tempname, extension)))): + tempname = "{0}-{1}".format(recordname, count) + count += 1 + + recordname = "%s.%s" % (tempname, extension) + + return recordname + + +def make_record_name(presentation): + """Create an 'EVENT-ROOM-SPEAKER-TITLE' record name using presentation metadata.""" + tags = [ + make_shortname(presentation.event), + make_shortname(presentation.room), + make_shortname(presentation.speaker), + make_shortname(presentation.title), + ] + record_name = unicode('-'.join(tag for tag in tags if tag)) + + # Convert unicode filenames to their equivalent ascii so that + # we don't run into issues with gstreamer or filesystems. + safe_record_name = unicodedata.normalize('NFKD', record_name).encode('ascii', 'ignore') + + return safe_record_name or 'default' + + +def make_shortname(string): + """Returns the first 6 characters of a string in uppercase. + + Strip out non alpha-numeric characters, spaces, and most punctuation. + """ + bad_chars = set("!@#$%^&*()+=|:;{}[]',? <>~`/\\") + string = "".join(ch for ch in string if ch not in bad_chars) + return string[0:6].upper() + + +### +### Handy functions for reseting Freeseer configuration +### + + +def reset(configdir): + """Deletes the Freeseer configuration directory""" + if validate_configdir(configdir): + print('This will wipe out your freeseer configuration directory.') + if confirm_yes() is True: + shutil.rmtree(configdir) + else: + print("%s is not a invalid configuration directory." % configdir) + + +def reset_configuration(configdir, profile='default'): + """Deletes the Freeseer configuration files freeseer.conf and plugin.conf""" + if profile is None: + profile = 'default' + + if validate_configdir(configdir): + freeseer_conf = os.path.join(configdir, 'profiles', profile, 'freeseer.conf') + plugin_conf = os.path.join(configdir, 'profiles', profile, 'plugin.conf') + + if os.path.exists(freeseer_conf): + os.remove(freeseer_conf) + + if os.path.exists(plugin_conf): + os.remove(plugin_conf) + else: + print("%s is not a invalid configuration directory." % configdir) + + +def reset_database(configdir, profile='default'): + """Deletes the Freeseer database file""" + if profile is None: + profile = 'default' + + if validate_configdir(configdir): + dbfile = os.path.join(configdir, 'profiles', profile, 'presentations.db') + + if os.path.exists(dbfile): + os.remove(dbfile) + else: + print("%s is not a invalid configuration directory." % configdir) + + +def validate_configdir(configdir): + """Validate that the configdir is not one of the blacklisted directories""" + if (configdir and configdir != '/' and + configdir != '~' and + configdir != os.path.abspath(os.path.expanduser('~'))): + return True + + return False + + +def confirm_yes(): + """Prompts the user to confirm by typing 'yes' in response""" + confirm = raw_input("Enter 'yes' to confirm: ") + if confirm == 'yes': + return True + return False diff --git a/src/freeseer/framework/youtube.py b/src/freeseer/framework/youtube.py index c6be7afc..ba8c93b8 100644 --- a/src/freeseer/framework/youtube.py +++ b/src/freeseer/framework/youtube.py @@ -23,7 +23,7 @@ # http://wiki.github.com/Freeseer/freeseer/ -import httplib +import http.client import httplib2 import logging import os @@ -58,13 +58,13 @@ class YoutubeService(object): RETRIABLE_EXCEPTIONS = ( httplib2.HttpLib2Error, IOError, - httplib.NotConnected, - httplib.IncompleteRead, - httplib.ImproperConnectionState, - httplib.CannotSendRequest, - httplib.CannotSendHeader, - httplib.ResponseNotReady, - httplib.BadStatusLine + http.client.NotConnected, + http.client.IncompleteRead, + http.client.ImproperConnectionState, + http.client.CannotSendRequest, + http.client.CannotSendHeader, + http.client.ResponseNotReady, + http.client.BadStatusLine ) RETRIABLE_STATUS_CODES = (500, 502, 503, 504) diff --git a/src/freeseer/frontend/cli.py b/src/freeseer/frontend/cli.py index 898963d7..4449e705 100644 --- a/src/freeseer/frontend/cli.py +++ b/src/freeseer/frontend/cli.py @@ -77,8 +77,8 @@ def setup_parser_record(subparsers): """Setup the record command parser""" parser = subparsers.add_parser('record', help='Freeseer recording functions') parser.add_argument("-t", "--talk", type=int, help="Talk ID of the talk you would like to record") - parser.add_argument("-f", "--filename", type=unicode, help="Record to filename") - parser.add_argument("-p", "--profile", type=unicode, help="Use profile") + parser.add_argument("-f", "--filename", type=str, help="Record to filename") + parser.add_argument("-p", "--profile", type=str, help="Use profile") parser.add_argument("-s", "--show-talks", help="Shows all talks", action="store_true") @@ -107,7 +107,7 @@ def setup_parser_config_reset(subparsers): configuration - Resets Freeseer configuration (removes freeseer.conf and plugins.conf) database - Resets Freeseer database (removes presentations.db) """) - parser.add_argument("-p", "--profile", type=unicode, help="Profile to reset (Default: default)") + parser.add_argument("-p", "--profile", type=str, help="Profile to reset (Default: default)") def setup_parser_config_youtube(subparsers): @@ -124,10 +124,10 @@ def setup_parser_talk(subparsers): """Setup the talk command parser""" parser = subparsers.add_parser('talk', help='Freeseer talk database functions') parser.add_argument("action", choices=['add', 'remove', 'clear', 'list'], nargs='?') - parser.add_argument("-t", "--title", type=unicode, help="Title") - parser.add_argument("-s", "--speaker", type=unicode, help="Speaker") - parser.add_argument("-r", "--room", type=unicode, help="Room") - parser.add_argument("-e", "--event", type=unicode, help="Event") + parser.add_argument("-t", "--title", type=str, help="Title") + parser.add_argument("-s", "--speaker", type=str, help="Speaker") + parser.add_argument("-r", "--room", type=str, help="Room") + parser.add_argument("-e", "--event", type=str, help="Event") parser.add_argument("-i", "--talk-id", type=int, help="Talk ID") @@ -155,7 +155,7 @@ def setup_parser_upload_youtube(subparsers): def setup_parser_server(subparsers): """Setup server command parser""" parser = subparsers.add_parser("server", help="Setup a freeseer restful server") - parser.add_argument("-f", "--filename", type=unicode, help="file to load recordings") + parser.add_argument("-f", "--filename", type=str, help="file to load recordings") def parse_args(parser, parse_args=None): @@ -242,7 +242,7 @@ def parse_args(parser, parse_args=None): elif args.action == "list": talks_query = db.get_talks() talks_table = [] - while talks_query.next(): + while next(talks_query): record = talks_query.record() talks_table.append([ talks_query.value(record.indexOf('id')).toString(), @@ -251,7 +251,7 @@ def parse_args(parser, parse_args=None): talks_query.value(record.indexOf('event')).toString(), ]) if talks_table: - print(tabulate(talks_table, headers=["ID", "Title", "Speaker", "Event"])) + print((tabulate(talks_table, headers=["ID", "Title", "Speaker", "Event"]))) else: print("No talks present.") diff --git a/src/freeseer/frontend/cli.py.bak b/src/freeseer/frontend/cli.py.bak new file mode 100644 index 00000000..898963d7 --- /dev/null +++ b/src/freeseer/frontend/cli.py.bak @@ -0,0 +1,343 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# freeseer - vga/presentation capture software +# +# Copyright (C) 2013, 2014 Free and Open Source Software Learning Centre +# http://fosslc.org +# +# This program 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. +# +# This program 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 . + +# For support, questions, suggestions or any other inquiries, visit: +# http://wiki.github.com/Freeseer/freeseer/ + + +import argparse +import signal +import sys +import textwrap + +import pygst +import yapsy +from PyQt4 import QtCore +from tabulate import tabulate + +from freeseer import __version__ +from freeseer import settings +from freeseer.frontend.upload import youtube + +signal.signal(signal.SIGINT, signal.SIG_DFL) + + +def setup_parser(): + """Initialize the Argument Parser""" + parser = argparse.ArgumentParser(description='Freeseer Recording Utility', + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument("-v", "--version", action='version', + version=textwrap.dedent('''\ + Freeseer {version} ({platform}) + Python {pymajor}.{pyminor}.{pymicro} + PyGst {pygst_version} + PyQt {pyqt_version} + Qt {qt_version} + Yapsy {yapsy_version} + '''.format(version=__version__, + platform=sys.platform, + pymajor=sys.version_info.major, + pyminor=sys.version_info.minor, + pymicro=sys.version_info.micro, + pygst_version=pygst._pygst_version, + pyqt_version=QtCore.PYQT_VERSION_STR, + qt_version=QtCore.QT_VERSION_STR, + yapsy_version=yapsy.__version__))) + + # Configure Subparsers + subparsers = parser.add_subparsers(dest='app', help='Command List') + setup_parser_record(subparsers) + setup_parser_config(subparsers) + setup_parser_talk(subparsers) + setup_parser_report(subparsers) + setup_parser_upload(subparsers) + setup_parser_server(subparsers) + return parser + + +def setup_parser_record(subparsers): + """Setup the record command parser""" + parser = subparsers.add_parser('record', help='Freeseer recording functions') + parser.add_argument("-t", "--talk", type=int, help="Talk ID of the talk you would like to record") + parser.add_argument("-f", "--filename", type=unicode, help="Record to filename") + parser.add_argument("-p", "--profile", type=unicode, help="Use profile") + parser.add_argument("-s", "--show-talks", help="Shows all talks", action="store_true") + + +### +### Config Parser and Subparsers +### + +def setup_parser_config(subparsers): + """Setup the config command parser""" + parser = subparsers.add_parser('config', help='Freeseer configuration functions') + subparsers = parser.add_subparsers(dest="config_service") + setup_parser_config_reset(subparsers) + setup_parser_config_youtube(subparsers) + + +def setup_parser_config_reset(subparsers): + """Setup reset command parser""" + parser = subparsers.add_parser("reset", help="Reset Freeseer configuration and database", + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument("reset", + choices=['all', 'configuration', 'database'], + help="""Resets Freeseer (default: all) + + Options: + all - Resets Freeseer (removes the Freeseer configuration directory, thus clearing logs, settings, and talks) + configuration - Resets Freeseer configuration (removes freeseer.conf and plugins.conf) + database - Resets Freeseer database (removes presentations.db) + """) + parser.add_argument("-p", "--profile", type=unicode, help="Profile to reset (Default: default)") + + +def setup_parser_config_youtube(subparsers): + """Setup Youtube config parser""" + from oauth2client import tools + # Inherent Google API argparser + parser = subparsers.add_parser("youtube", help="Obtain OAuth2 token for Youtube access", parents=[tools.argparser]) + defaults = youtube.get_defaults() + parser.add_argument("-c", "--client-secrets", help="Path to client secrets file", default=defaults["client_secrets"]) + parser.add_argument("-t", "--token", help="Location to save token file", default=defaults["oauth2_token"]) + + +def setup_parser_talk(subparsers): + """Setup the talk command parser""" + parser = subparsers.add_parser('talk', help='Freeseer talk database functions') + parser.add_argument("action", choices=['add', 'remove', 'clear', 'list'], nargs='?') + parser.add_argument("-t", "--title", type=unicode, help="Title") + parser.add_argument("-s", "--speaker", type=unicode, help="Speaker") + parser.add_argument("-r", "--room", type=unicode, help="Room") + parser.add_argument("-e", "--event", type=unicode, help="Event") + parser.add_argument("-i", "--talk-id", type=int, help="Talk ID") + + +def setup_parser_report(subparsers): + """Setup the report command parser""" + subparsers.add_parser('report', help='Freeseer reporting functions') + + +def setup_parser_upload(subparsers): + """Setup upload tool command parser""" + parser = subparsers.add_parser("upload", help="Upload file tool") + subparsers = parser.add_subparsers(dest="upload_service", help="Service to upload with") + setup_parser_upload_youtube(subparsers) + + +def setup_parser_upload_youtube(subparsers): + """Setup youtube upload command parser""" + defaults = youtube.get_defaults() + parser = subparsers.add_parser("youtube", help="Youtube upload command line tool") + parser.add_argument("files", help="Path to videos or video directories to upload", nargs="*", default=[defaults["video_directory"]]) + parser.add_argument("-t", "--token", help="Path to OAuth2 token", default=defaults["oauth2_token"]) + parser.add_argument("-y", "--yes", help="Automatic yes to prompts", action="store_true") + + +def setup_parser_server(subparsers): + """Setup server command parser""" + parser = subparsers.add_parser("server", help="Setup a freeseer restful server") + parser.add_argument("-f", "--filename", type=unicode, help="file to load recordings") + + +def parse_args(parser, parse_args=None): + if len(sys.argv) == 1: # No arguments passed + launch_recordapp() + + args = parser.parse_args(parse_args) + + if args.app == 'record': + if len(sys.argv) == 2: # No 'record' arguments passed + launch_recordapp() + + import gobject + # Must declare after argparse otherwise GStreamer will take over the cli help + from freeseer.frontend.record.RecordingController import RecordingController + + # TODO: Abstract the database stuff away from here as it's only + # used in conjunction with talks. + if args.profile is None: # Profile is an optional parameter + args.profile = 'default' + profile = settings.profile_manager.get(args.profile) + config = profile.get_config('freeseer.conf', settings.FreeseerConfig, + storage_args=['Global'], read_only=False) + # XXX: There should only be 1 database per user. Workaround for this + # is to put it in the 'default' profile. + db = settings.profile_manager.get().get_database() + + app = RecordingController(profile, db, config, cli=True) + + if args.talk: + if app.record_talk_id(args.talk): + sys.exit(gobject.MainLoop().run()) + elif args.filename: + if app.record_filename(args.filename): + sys.exit(gobject.MainLoop().run()) + elif args.show_talks: + app.print_talks() + + elif args.app == 'config': + if len(sys.argv) == 2: # No 'config' arguments passed + launch_configtool() + + from freeseer.settings import configdir + from freeseer.framework.util import reset + from freeseer.framework.util import reset_configuration + from freeseer.framework.util import reset_database + from freeseer.framework.youtube import YoutubeService + + if args.config_service == "reset": + if args.reset == "all": + reset(configdir) + elif args.reset == "configuration": + reset_configuration(configdir, args.profile) + elif args.reset == "database": + reset_database(configdir, args.profile) + else: + print("Invalid reset option.") + + elif args.config_service == "youtube": + YoutubeService.acquire_token(args.client_secrets, args.token, args) + + elif args.app == 'talk': + if len(sys.argv) == 2: # No 'talk' arguments passed + launch_talkeditor() + + from freeseer.framework.presentation import Presentation + + profile = settings.profile_manager.get() + db = profile.get_database() + + if args.action == "add": + presentation = Presentation(args.title, + speaker=args.speaker, + room=args.room, + event=args.event) + db.insert_presentation(presentation) + + elif args.action == "remove": + db.delete_presentation(args.talk_id) + + elif args.action == "clear": + db.clear_database() + + elif args.action == "list": + talks_query = db.get_talks() + talks_table = [] + while talks_query.next(): + record = talks_query.record() + talks_table.append([ + talks_query.value(record.indexOf('id')).toString(), + talks_query.value(record.indexOf('title')).toString(), + talks_query.value(record.indexOf('speaker')).toString(), + talks_query.value(record.indexOf('event')).toString(), + ]) + if talks_table: + print(tabulate(talks_table, headers=["ID", "Title", "Speaker", "Event"])) + else: + print("No talks present.") + + else: + print("Invalid option.") + + elif args.app == 'report': + if len(sys.argv) == 2: # No 'report' arguments passed + launch_reporteditor() + + elif args.app == 'upload': + if args.upload_service == 'youtube': + youtube.upload(args.files, args.token, args.yes) + + elif args.app == 'server': + if args.filename: + launch_server(args.filename) + else: + launch_server() + + +def launch_recordapp(): + """Launch the Recording GUI if no arguments are passed""" + from PyQt4.QtGui import QApplication + from freeseer.frontend.record.record import RecordApp + + profile = settings.profile_manager.get() + config = profile.get_config('freeseer.conf', settings.FreeseerConfig, + storage_args=['Global'], read_only=False) + + app = QApplication(sys.argv) + main = RecordApp(profile, config) + main.show() + sys.exit(app.exec_()) + + +def launch_configtool(): + """Launch Freeseer Configuration GUI if no arguments are passed""" + from PyQt4 import QtGui + from freeseer.frontend.configtool.configtool import ConfigToolApp + + profile = settings.profile_manager.get() + config = profile.get_config('freeseer.conf', settings.FreeseerConfig, + storage_args=['Global'], read_only=False) + + app = QtGui.QApplication(sys.argv) + main = ConfigToolApp(profile, config) + main.show() + sys.exit(app.exec_()) + + +def launch_talkeditor(): + """Launch the Talk Editor GUI if no arguments are passed""" + from PyQt4.QtGui import QApplication + from freeseer.frontend.talkeditor.talkeditor import TalkEditorApp + + profile = settings.profile_manager.get() + config = profile.get_config('freeseer.conf', settings.FreeseerConfig, + storage_args=['Global'], read_only=True) + db = profile.get_database() + + app = QApplication(sys.argv) + main = TalkEditorApp(config, db) + main.show() + sys.exit(app.exec_()) + + +def launch_reporteditor(): + """Launch the Report Editor GUI""" + import sys + from PyQt4 import QtGui + from freeseer.frontend.reporteditor.reporteditor import ReportEditorApp + + profile = settings.profile_manager.get() + config = profile.get_config('freeseer.conf', settings.FreeseerConfig, + storage_args=['Global'], read_only=True) + db = profile.get_database() + + app = QtGui.QApplication(sys.argv) + main = ReportEditorApp(config, db) + main.show() + sys.exit(app.exec_()) + + +def launch_server(storage_file="recording_storage"): + """Launch the Server""" + import freeseer.frontend.controller.server as server + + server.start_server(storage_file) diff --git a/src/freeseer/frontend/configtool/AVWidget.py b/src/freeseer/frontend/configtool/AVWidget.py index 5c1269cb..7452a654 100644 --- a/src/freeseer/frontend/configtool/AVWidget.py +++ b/src/freeseer/frontend/configtool/AVWidget.py @@ -212,7 +212,7 @@ def __init__(self, parent=None): # self.mainLayout.insertSpacerItem(0, QtGui.QSpacerItem(0, fontSize * 2)) - self.title = QtGui.QLabel(u"{0} Recording {1}".format(u'

', u'

')) + self.title = QtGui.QLabel("{0} Recording {1}".format('

', '

')) self.mainLayout.insertWidget(0, self.title) diff --git a/src/freeseer/frontend/configtool/GeneralWidget.py b/src/freeseer/frontend/configtool/GeneralWidget.py index 4566e1c6..68b6b469 100644 --- a/src/freeseer/frontend/configtool/GeneralWidget.py +++ b/src/freeseer/frontend/configtool/GeneralWidget.py @@ -61,7 +61,7 @@ def __init__(self, parent=None): # Heading # - self.title = QtGui.QLabel(u"{0} General {1}".format(u'

', u'

')) + self.title = QtGui.QLabel("{0} General {1}".format('

', '

')) self.mainLayout.insertWidget(0, self.title) self.mainLayout.insertSpacerItem(1, QtGui.QSpacerItem(0, fontSize * 2)) diff --git a/src/freeseer/frontend/configtool/PluginWidget.py b/src/freeseer/frontend/configtool/PluginWidget.py index 4909d4c2..53235d22 100644 --- a/src/freeseer/frontend/configtool/PluginWidget.py +++ b/src/freeseer/frontend/configtool/PluginWidget.py @@ -89,7 +89,7 @@ def __init__(self, parent=None): def treeViewSelect(self): item = self.list.currentItem() key = str(item.text(0)) - if key in self.pluginMetadata.keys(): + if key in list(self.pluginMetadata.keys()): self.showDetails(key) else: self.hideDetails() diff --git a/src/freeseer/frontend/configtool/configtool.py b/src/freeseer/frontend/configtool/configtool.py index 58b8df0f..310ab2fc 100644 --- a/src/freeseer/frontend/configtool/configtool.py +++ b/src/freeseer/frontend/configtool/configtool.py @@ -225,7 +225,7 @@ def retranslate(self): # # AV Widget # - self.avWidget.title.setText(u"{0} {1} {2}".format(u'

', self.app.translate("ConfigToolApp", "Recording"), u'

')) + self.avWidget.title.setText("{0} {1} {2}".format('

', self.app.translate("ConfigToolApp", "Recording"), '

')) self.avWidget.audioGroupBox.setTitle(self.app.translate("ConfigToolApp", "Audio Input")) self.avWidget.audioMixerLabel.setText(self.app.translate("ConfigToolApp", "Audio Mixer")) @@ -237,7 +237,7 @@ def retranslate(self): self.avWidget.fileGroupBox.setTitle(self.app.translate("ConfigToolApp", "Record to File")) self.avWidget.fileDirLabel.setText(self.app.translate("ConfigToolApp", "Record Directory")) - self.avWidget.fileDirPushButton.setText(u"{}...".format(self.app.translate("ConfigToolApp", "Browse"))) + self.avWidget.fileDirPushButton.setText("{}...".format(self.app.translate("ConfigToolApp", "Browse"))) self.avWidget.fileLabel.setText(self.app.translate("ConfigToolApp", "File Format")) self.avWidget.fileSetupPushButton.setToolTip(self.app.translate("ConfigToolApp", "Setup")) @@ -496,13 +496,13 @@ def setup_audio_quality(self): if file_configurable: file_config_layout = file_output_plugin.plugin_object.get_audio_quality_layout() - self.audio_quality_dialog_layout.addWidget(QtGui.QLabel(u'File Output'), 0, 0, 1, 2, QtCore.Qt.AlignHCenter) + self.audio_quality_dialog_layout.addWidget(QtGui.QLabel('File Output'), 0, 0, 1, 2, QtCore.Qt.AlignHCenter) self.audio_quality_dialog_layout.addLayout(file_config_layout, 1, 0) if stream_configurable: stream_config_layout = stream_output_plugin.plugin_object.get_audio_quality_layout() column_count = self.audio_quality_dialog_layout.columnCount() - self.audio_quality_dialog_layout.addWidget(QtGui.QLabel(u'Stream Output'), 0, column_count, 1, 2, QtCore.Qt.AlignHCenter) + self.audio_quality_dialog_layout.addWidget(QtGui.QLabel('Stream Output'), 0, column_count, 1, 2, QtCore.Qt.AlignHCenter) self.audio_quality_dialog_layout.addLayout(stream_config_layout, 1, column_count) self.audio_quality_dialog_layout.addWidget(self.audio_quality_dialog.closeButton, 2, 0, 1, self.audio_quality_dialog_layout.columnCount()) @@ -561,13 +561,13 @@ def setup_video_quality(self): if file_configurable: file_config_layout = file_output_plugin.plugin_object.get_video_quality_layout() - self.video_quality_dialog_layout.addWidget(QtGui.QLabel(u'File Output'), 0, 0, 1, 2, QtCore.Qt.AlignHCenter) + self.video_quality_dialog_layout.addWidget(QtGui.QLabel('File Output'), 0, 0, 1, 2, QtCore.Qt.AlignHCenter) self.video_quality_dialog_layout.addLayout(file_config_layout, 1, 0) if stream_configurable: stream_config_layout = stream_output_plugin.plugin_object.get_video_quality_layout() column_count = self.video_quality_dialog_layout.columnCount() - self.video_quality_dialog_layout.addWidget(QtGui.QLabel(u'Stream Output'), 0, column_count, 1, 2, QtCore.Qt.AlignHCenter) + self.video_quality_dialog_layout.addWidget(QtGui.QLabel('Stream Output'), 0, column_count, 1, 2, QtCore.Qt.AlignHCenter) self.video_quality_dialog_layout.addLayout(stream_config_layout, 1, column_count) self.video_quality_dialog_layout.addWidget(self.video_quality_dialog.closeButton, 2, 0, 1, self.video_quality_dialog_layout.columnCount()) @@ -750,7 +750,7 @@ def show_plugin_widget_dialog(self, widget, name): self.dialog.closeButton = QtGui.QPushButton("Close") self.dialog_layout.addWidget(self.dialog.closeButton) self.connect(self.dialog.closeButton, QtCore.SIGNAL('clicked()'), self.dialog.close) - self.dialog.setWindowTitle(u'{} Setup'.format(name)) + self.dialog.setWindowTitle('{} Setup'.format(name)) self.dialog.setModal(True) self.dialog.show() diff --git a/src/freeseer/frontend/controller/recording.py b/src/freeseer/frontend/controller/recording.py index 4c2e9eb3..af6ecfcd 100644 --- a/src/freeseer/frontend/controller/recording.py +++ b/src/freeseer/frontend/controller/recording.py @@ -89,7 +89,7 @@ def configure_recording(): recording.next_id = 1 recording.media_dict = {} - for key, value in media_info.iteritems(): + for key, value in media_info.items(): new_media = Multimedia(recording.config, recording.plugin_manager) if value['null_multimeda']: new_media.current_state = Multimedia.NULL @@ -122,7 +122,7 @@ def configure_recording(): @http_response(200) def get_all_recordings(): """Returns list of all recordings.""" - return {'recordings': recording.media_dict.keys()} + return {'recordings': list(recording.media_dict.keys())} @recording.route('/recordings/', methods=['GET']) diff --git a/src/freeseer/frontend/qtcommon/AboutDialog.py b/src/freeseer/frontend/qtcommon/AboutDialog.py index b3d4ed78..ea70bc22 100644 --- a/src/freeseer/frontend/qtcommon/AboutDialog.py +++ b/src/freeseer/frontend/qtcommon/AboutDialog.py @@ -39,10 +39,10 @@ from freeseer.frontend.qtcommon import resource # noqa from freeseer.frontend.qtcommon.AboutWidget import AboutWidget -RECORD_BUTTON_ARTIST = u'Sekkyumu' -RECORD_BUTTON_LINK = u'http://sekkyumu.deviantart.com/' -HEADPHONES_ARTIST = u'Ben Fleming' -HEADPHONES_LINK = u'http://mediadesign.deviantart.com/' +RECORD_BUTTON_ARTIST = 'Sekkyumu' +RECORD_BUTTON_LINK = 'http://sekkyumu.deviantart.com/' +HEADPHONES_ARTIST = 'Ben Fleming' +HEADPHONES_LINK = 'http://mediadesign.deviantart.com/' class AboutDialog(QDialog): diff --git a/src/freeseer/frontend/qtcommon/AboutWidget.py b/src/freeseer/frontend/qtcommon/AboutWidget.py index 5178ecc6..a51aa9cc 100644 --- a/src/freeseer/frontend/qtcommon/AboutWidget.py +++ b/src/freeseer/frontend/qtcommon/AboutWidget.py @@ -51,10 +51,10 @@ from freeseer.frontend.qtcommon.dpi_adapt_qtgui import QWidgetWithDpi -RECORD_BUTTON_ARTIST = u'Sekkyumu' -RECORD_BUTTON_LINK = u'http://sekkyumu.deviantart.com/' -HEADPHONES_ARTIST = u'Ben Fleming' -HEADPHONES_LINK = u'http://mediadesign.deviantart.com/' +RECORD_BUTTON_ARTIST = 'Sekkyumu' +RECORD_BUTTON_LINK = 'http://sekkyumu.deviantart.com/' +HEADPHONES_ARTIST = 'Ben Fleming' +HEADPHONES_LINK = 'http://mediadesign.deviantart.com/' class AboutWidget(QWidgetWithDpi): @@ -137,17 +137,17 @@ def retranslate(self, language=None): "version 3. This software is provided 'as-is',without any express or implied warranty. In " "no event will the authors be held liable for any damages arising from the use of this software.") - self.aboutInfoString = u'

' + NAME.capitalize() + u'

' + \ - u'
' + self.uiTranslator.translate("AboutDialog", "Version") + \ - ": " + __version__ + u'' + \ - u'

' + self.descriptionString + u'

' + \ - u'

' + self.copyrightString + u'

' + \ - u'

' + URL + u'

' \ - u'

' + self.licenseTextString + u'

' \ - u'

' + self.uiTranslator.translate("AboutDialog", "Record button graphics by") + \ - u': ' + RECORD_BUTTON_ARTIST + u'

' \ - u'

' + self.uiTranslator.translate("AboutDialog", "Headphones graphics by") + \ - u': ' + HEADPHONES_ARTIST + u'


' + self.aboutInfoString = '

' + NAME.capitalize() + '

' + \ + '
' + self.uiTranslator.translate("AboutDialog", "Version") + \ + ": " + __version__ + '' + \ + '

' + self.descriptionString + '

' + \ + '

' + self.copyrightString + '

' + \ + '

' + URL + '

' \ + '

' + self.licenseTextString + '

' \ + '

' + self.uiTranslator.translate("AboutDialog", "Record button graphics by") + \ + ': ' + RECORD_BUTTON_ARTIST + '

' \ + '

' + self.uiTranslator.translate("AboutDialog", "Headphones graphics by") + \ + ': ' + HEADPHONES_ARTIST + '


' self.aboutInfo.setText(self.aboutInfoString) # --- End Main Text diff --git a/src/freeseer/frontend/record/RecordingController.py b/src/freeseer/frontend/record/RecordingController.py index 409c2cc2..b2427044 100644 --- a/src/freeseer/frontend/record/RecordingController.py +++ b/src/freeseer/frontend/record/RecordingController.py @@ -69,12 +69,12 @@ def print_talks(self): print("ID: Speaker - Title") print("-------------------") - while(query.next()): - talkid = unicode(query.value(0).toString()) - title = unicode(query.value(1).toString()) - speaker = unicode(query.value(2).toString()) + while(next(query)): + talkid = str(query.value(0).toString()) + title = str(query.value(1).toString()) + speaker = str(query.value(2).toString()) - print("{talkid}: {speaker} - {title}".format(talkid=talkid, speaker=speaker, title=title)) + print(("{talkid}: {speaker} - {title}".format(talkid=talkid, speaker=speaker, title=title))) ### ### Convenience commands diff --git a/src/freeseer/frontend/record/record.py b/src/freeseer/frontend/record/record.py index 726504ab..08cdb009 100644 --- a/src/freeseer/frontend/record/record.py +++ b/src/freeseer/frontend/record/record.py @@ -235,7 +235,7 @@ def retranslate(self): elif self.actionAutoRecord.isChecked(): self.mainWidget.statusLabel.setText(self.autoRecordString) else: - self.mainWidget.statusLabel.setText(u"{} {} --- {} ".format(self.freeSpaceString, + self.mainWidget.statusLabel.setText("{} {} --- {} ".format(self.freeSpaceString, get_free_space(self.config.videodir), self.idleString)) @@ -363,7 +363,7 @@ def toggle_gui(state): if self.load_backend(): toggle_gui(True) self.controller.pause() - self.mainWidget.statusLabel.setText(u"{} {} --- {} ".format(self.freeSpaceString, + self.mainWidget.statusLabel.setText("{} {} --- {} ".format(self.freeSpaceString, get_free_space(self.config.videodir), self.readyString)) else: @@ -409,7 +409,7 @@ def record(self): self.mainWidget.pauseButton.setEnabled(False) self.recordAction.setText(self.recordString) self.mainWidget.audioSlider.setValue(0) - self.mainWidget.statusLabel.setText(u"{} {} --- {} ".format(self.freeSpaceString, + self.mainWidget.statusLabel.setText("{} {} --- {} ".format(self.freeSpaceString, get_free_space(self.config.videodir), self.idleString)) @@ -460,7 +460,7 @@ def auto_record(self, state): if self.current_room: self.autoTalks = self.db.get_talks_by_room_and_time(self.current_room) # Start recording if there are talks in database that can be auto-recorded - if self.autoTalks.next(): + if next(self.autoTalks): # Set the cursor back to before the first record so that single_auto_record works properly self.autoTalks.previous() self._enable_disable_gui(True) @@ -496,7 +496,7 @@ def single_auto_record(self): self.recorded = False log.debug("Auto-recording for the current talk stopped.") - if self.autoTalks.next(): + if next(self.autoTalks): starttime = QtCore.QTime.fromString(self.autoTalks.value(8).toString()) endtime = QtCore.QTime.fromString(self.autoTalks.value(9).toString()) currenttime = QtCore.QTime.currentTime() @@ -561,7 +561,7 @@ def load_backend(self): # If current presentation is no existant (empty talk database) # use a default recording name. else: - presentation = Presentation(title=unicode("default")) + presentation = Presentation(title=str("default")) initialized, self.recently_recorded_video = self.controller.load_backend(presentation) if initialized: @@ -580,7 +580,7 @@ def update_timer(self): self.time_seconds = 0 self.time_minutes += 1 - self.mainWidget.statusLabel.setText(u"{} {} --- {} {} --- {}".format(self.elapsedTimeString, + self.mainWidget.statusLabel.setText("{} {} --- {} {} --- {}".format(self.elapsedTimeString, frmt_time, self.freeSpaceString, get_free_space(self.config.videodir), diff --git a/src/freeseer/frontend/record/record.py.bak b/src/freeseer/frontend/record/record.py.bak new file mode 100644 index 00000000..726504ab --- /dev/null +++ b/src/freeseer/frontend/record/record.py.bak @@ -0,0 +1,762 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# freeseer - vga/presentation capture software +# +# Copyright (C) 2011, 2014 Free and Open Source Software Learning Centre +# http://fosslc.org +# +# This program 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. +# +# This program 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 . + +# For support, questions, suggestions or any other inquiries, visit: +# http://wiki.github.com/Freeseer/freeseer/ + +import logging +import os +import subprocess +import sys +import functools + +from PyQt4 import QtGui, QtCore +from PyQt4.QtGui import QCursor + +try: + _fromUtf8 = QtCore.QString.fromUtf8 +except AttributeError: + _fromUtf8 = lambda s: s + +from freeseer.framework.presentation import Presentation +from freeseer.framework.failure import Failure +from freeseer.framework.util import get_free_space +from freeseer.frontend.qtcommon.FreeseerApp import FreeseerApp +from freeseer.frontend.qtcommon.log import LogStatusWidget +from freeseer.frontend.configtool.configtool import ConfigToolApp +from freeseer.frontend.record.RecordingController import RecordingController +from freeseer.frontend.record.RecordingWidget import RecordingWidget +from freeseer.frontend.record.AutoRecordWidget import AutoRecordWidget +from freeseer.frontend.record.ReportDialog import ReportDialog +from freeseer.frontend.talkeditor.talkeditor import TalkEditorApp + +log = logging.getLogger(__name__) + + +class RecordApp(FreeseerApp): + """Freeseer's main GUI class.""" + + def __init__(self, profile, config): + super(RecordApp, self).__init__(config) + + self.db = profile.get_database() + self.controller = RecordingController(profile, self.db, self.config) + + self.recently_recorded_video = None + + self.resize(550, 450) + + # Setup custom widgets + self.mainWidget = RecordingWidget() + self.setCentralWidget(self.mainWidget) + self.reportWidget = ReportDialog() + self.reportWidget.setModal(True) + self.autoRecordWidget = AutoRecordWidget() + self.configToolApp = ConfigToolApp(profile, config) + self.configToolApp.setWindowModality(QtCore.Qt.ApplicationModal) + self.configToolApp.setWindowFlags(QtCore.Qt.Dialog) + self.talkEditorApp = TalkEditorApp(self.config, self.db) + self.talkEditorApp.setWindowModality(QtCore.Qt.ApplicationModal) + self.talkEditorApp.setWindowFlags(QtCore.Qt.Dialog) + + self.logStatusWidget = LogStatusWidget(self.logDialog) + self.statusBar().addPermanentWidget(self.logStatusWidget, 1) + self.statusBar().addPermanentWidget(self.mainWidget.statusLabel) + + # Initialize geometry, to be used for restoring window positioning. + self.geometry = None + self.current_event = None + self.current_room = None + self.controller.set_window_id(self.mainWidget.previewWidget.winId()) + self.controller.set_audio_feedback_handler(self.audio_feedback) + + # Set timer for recording how much time elapsed during a recording + self.reset_timer() + self.timer = QtCore.QTimer(self) + self.timer.timeout.connect(self.update_timer) + + # Initialize variables for auto-recording + self.singleID = None + self.timeUntilStart = None + self.timeUntilEnd = None + self.autoTalks = None + self.recorded = False + self.beforeStartTimer = QtCore.QTimer(self) + self.beforeStartTimer.timeout.connect(self.start_single_record) + self.beforeEndTimer = QtCore.QTimer(self) + self.beforeEndTimer.timeout.connect(self.single_auto_record) + + # + # Setup Menubar + # + + # Build the options Menu, TalkEditor and ConfigTool + self.menuOptions = QtGui.QMenu(self.menubar) + self.menuOptions.setObjectName(_fromUtf8("menuOptions")) + self.menubar.insertMenu(self.menuHelp.menuAction(), self.menuOptions) + self.actionConfigTool = QtGui.QAction(self) + self.actionConfigTool.setShortcut("Ctrl+C") + self.actionConfigTool.setObjectName(_fromUtf8("actionConfigTool")) + self.actionTalkEditor = QtGui.QAction(self) + self.actionTalkEditor.setShortcut("Ctrl+E") + self.actionTalkEditor.setObjectName(_fromUtf8("actionTalkEditor")) + self.actionAutoRecord = QtGui.QAction(self) + leaveButtonShortcut = "Ctrl+R" + self.actionAutoRecord.setShortcut(leaveButtonShortcut) + self.actionAutoRecord.setCheckable(True) + self.actionAutoRecord.setObjectName(_fromUtf8("actionAutoRecord")) + self.menuOptions.addAction(self.actionConfigTool) + self.menuOptions.addAction(self.actionTalkEditor) + self.menuOptions.addAction(self.actionAutoRecord) + + folderIcon = QtGui.QIcon.fromTheme("folder") + self.actionOpenVideoFolder = QtGui.QAction(self) + self.actionOpenVideoFolder.setShortcut("Ctrl+O") + self.actionOpenVideoFolder.setObjectName(_fromUtf8("actionOpenVideoFolder")) + self.actionOpenVideoFolder.setIcon(folderIcon) + + self.actionReport = QtGui.QAction(self) + self.actionReport.setObjectName(_fromUtf8("actionReport")) + + # Actions + self.menuFile.insertAction(self.actionExit, self.actionOpenVideoFolder) + self.menuHelp.addAction(self.actionReport) + # --- End Menubar + + # + # Systray Setup + # + self.systray = QtGui.QSystemTrayIcon(self.icon) + self.systray.show() + self.systray.menu = QtGui.QMenu() + self.systray.setContextMenu(self.systray.menu) + + self.visibilityAction = QtGui.QAction(self) + self.recordAction = QtGui.QAction(self) + + self.systray.menu.addAction(self.visibilityAction) + self.systray.menu.addAction(self.recordAction) + + self.connect(self.visibilityAction, QtCore.SIGNAL('triggered()'), self.toggle_window_visibility) + self.connect(self.recordAction, QtCore.SIGNAL('triggered()'), self.toggle_record_button) + self.connect(self.systray, QtCore.SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), self._icon_activated) + # --- End Systray Setup + + # main tab connections + self.connect(self.mainWidget.eventComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_rooms_from_event) + self.connect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_dates_from_event_room) + self.connect(self.mainWidget.dateComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_date) + self.connect(self.mainWidget.talkComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.set_talk_tooltip) + self.connect(self.mainWidget.standbyButton, QtCore.SIGNAL("toggled(bool)"), self.standby) + self.connect(self.mainWidget.disengageButton, QtCore.SIGNAL("clicked()"), functools.partial(self.standby, state=False)) + self.connect(self.mainWidget.recordButton, QtCore.SIGNAL('clicked()'), self.record) + self.connect(self.mainWidget.pauseButton, QtCore.SIGNAL('toggled(bool)'), self.pause) + self.connect(self.mainWidget.audioFeedbackCheckbox, QtCore.SIGNAL('toggled(bool)'), self.toggle_audio_feedback) + self.connect(self.mainWidget.playButton, QtCore.SIGNAL('clicked()'), self.play_video) + + self.connect(self.autoRecordWidget.leaveButton, QtCore.SIGNAL('clicked()'), functools.partial(self.auto_record, state=False)) + self.autoRecordWidget.leaveButton.setShortcut(leaveButtonShortcut) + + # Main Window Connections + self.connect(self.actionConfigTool, QtCore.SIGNAL('triggered()'), self.open_configtool) + self.connect(self.actionTalkEditor, QtCore.SIGNAL('triggered()'), self.open_talkeditor) + self.connect(self.actionAutoRecord, QtCore.SIGNAL('toggled(bool)'), self.auto_record) + self.connect(self.actionOpenVideoFolder, QtCore.SIGNAL('triggered()'), self.open_video_directory) + self.connect(self.actionReport, QtCore.SIGNAL('triggered()'), self.show_report_widget) + + # + # ReportWidget Connections + # + self.connect(self.reportWidget.reportButton, QtCore.SIGNAL("clicked()"), self.report) + + self.load_settings() + + # Setup spacebar key. + self.mainWidget.pauseButton.setShortcut(QtCore.Qt.Key_Space) + self.mainWidget.pauseButton.setFocus() + + self.retranslate() + + ### + ### Translation Related + ### + def retranslate(self): + self.setWindowTitle(self.app.translate("RecordApp", "Freeseer - portable presentation recording station")) + # + # Reusable Strings + # + self.standbyString = self.app.translate("RecordApp", "Standby") + self.disengageString = self.app.translate("RecordApp", "Leave record-mode") + self.standbyTooltipString = self.app.translate("RecordApp", "Sets up the system for recording") + self.disengageTooltipString = self.app.translate("RecordApp", "Go back to edit talk information or select a different talk") + self.autoRecordString = self.app.translate("RecordApp", "Auto Record") + self.recordString = self.app.translate("RecordApp", "Record") + self.pauseString = self.app.translate("RecordApp", "Pause") + self.resumeString = self.app.translate("RecordApp", "Resume") + self.stopString = self.app.translate("RecordApp", "Stop") + self.stopAutoString = self.app.translate("RecordApp", "Stop Auto Record") + self.hideWindowString = self.app.translate("RecordApp", "Hide Main Window") + self.showWindowString = self.app.translate("RecordApp", "Show Main Window") + self.playVideoString = self.app.translate("RecordApp", "Play") + + # Status Bar messages + self.idleString = self.app.translate("RecordApp", "Idle.") + self.readyString = self.app.translate("RecordApp", "Ready.") + self.recordingString = self.app.translate("RecordApp", "Recording") + self.pausedString = self.app.translate("RecordApp", "Recording Paused.") + self.freeSpaceString = self.app.translate("RecordApp", "Free Space:") + self.elapsedTimeString = self.app.translate("RecordApp", "Elapsed Time:") + # --- End Reusable Strings + + if self.mainWidget.is_recording and self.mainWidget.pauseButton.isChecked(): + self.mainWidget.statusLabel.setText(self.pausedString) + elif self.mainWidget.is_recording and (not self.mainWidget.pauseButton.isChecked()): + self.mainWidget.statusLabel.setText(self.recordingString) + elif self.mainWidget.standbyButton.isChecked(): + self.mainWidget.statusLabel.setText(self.readyString) + elif self.actionAutoRecord.isChecked(): + self.mainWidget.statusLabel.setText(self.autoRecordString) + else: + self.mainWidget.statusLabel.setText(u"{} {} --- {} ".format(self.freeSpaceString, + get_free_space(self.config.videodir), + self.idleString)) + + # + # Menubar + # + self.menuOptions.setTitle(self.app.translate("RecordApp", "&Options")) + self.actionConfigTool.setText(self.app.translate("RecordApp", "&Configuration")) + self.actionTalkEditor.setText(self.app.translate("RecordApp", "&Edit Talks")) + self.actionAutoRecord.setText(self.autoRecordString) + self.actionOpenVideoFolder.setText(self.app.translate("RecordApp", "&Open Video Directory")) + self.actionReport.setText(self.app.translate("RecordApp", "&Report")) + # --- End Menubar + + # + # Systray + # + self.visibilityAction.setText(self.hideWindowString) + self.recordAction.setText(self.recordString) + # --- End Systray + + # + # RecordingWidget + # + self.mainWidget.disengageButton.setText(self.disengageString) + self.mainWidget.standbyButton.setText(self.standbyString) + self.mainWidget.standbyButton.setToolTip(self.standbyTooltipString) + self.mainWidget.disengageButton.setToolTip(self.disengageTooltipString) + if self.mainWidget.is_recording: + self.mainWidget.recordButton.setToolTip(self.stopString) + else: + self.mainWidget.recordButton.setToolTip(self.recordString) + self.mainWidget.pauseButton.setText(self.pauseString) + self.mainWidget.pauseButton.setToolTip(self.pauseString) + self.mainWidget.eventLabel.setText(self.app.translate("RecordApp", "Event")) + self.mainWidget.roomLabel.setText(self.app.translate("RecordApp", "Room")) + self.mainWidget.dateLabel.setText(self.app.translate("RecordApp", "Date")) + self.mainWidget.talkLabel.setText(self.app.translate("RecordApp", "Talk")) + # --- End RecordingWidget + + # + # ReportWidget + # + self.reportWidget.setWindowTitle(self.app.translate("RecordApp", "Reporting Tool")) + self.reportWidget.titleLabel.setText(self.app.translate("RecordApp", "Title:")) + self.reportWidget.speakerLabel.setText(self.app.translate("RecordApp", "Speaker:")) + self.reportWidget.eventLabel.setText(self.app.translate("RecordApp", "Event:")) + self.reportWidget.roomLabel.setText(self.app.translate("RecordApp", "Room:")) + self.reportWidget.startTimeLabel.setText(self.app.translate("RecordApp", "Start Time:")) + self.reportWidget.endTimeLabel.setText(self.app.translate("RecordApp", "End Time:")) + self.reportWidget.commentLabel.setText(self.app.translate("RecordApp", "Comment")) + self.reportWidget.releaseCheckBox.setText(self.app.translate("RecordApp", "Release Received")) + self.reportWidget.closeButton.setText(self.app.translate("RecordApp", "Close")) + self.reportWidget.reportButton.setText(self.app.translate("RecordApp", "Report")) + + # Logic for translating the report options + noissues = self.app.translate("RecordApp", "No Issues") + noaudio = self.app.translate("RecordApp", "No Audio") + novideo = self.app.translate("RecordApp", "No Video") + noaudiovideo = self.app.translate("RecordApp", "No Audio/Video") + self.reportWidget.options = [noissues, noaudio, novideo, noaudiovideo] + self.reportWidget.reportCombo.clear() + for i in self.reportWidget.options: + self.reportWidget.reportCombo.addItem(i) + # --- End ReportWidget + + self.logStatusWidget.retranslate() + + ### + ### UI Logic + ### + + def load_settings(self): + """Load settings for Freeseer""" + log.info('Loading settings...') + + # Load default language. + actions = self.menuLanguage.actions() + for action in actions: + if action.data().toString() == self.config.default_language: + action.setChecked(True) + self.translate(action) + break + + # Load Talks as a SQL Data Model. + self.load_event_list() + + def current_presentation(self): + """Creates a presentation object of the current presentation. + + Current presentation is the currently selected title on the GUI. + """ + #i = self.mainWidget.talkComboBox.currentIndex() + #p_id = self.mainWidget.talkComboBox.model().index(i, 1).data(QtCore.Qt.DisplayRole).toString() + return self.db.get_presentation(self.current_presentation_id()) + + def current_presentation_id(self): + """Returns the current selected presentation ID.""" + i = self.mainWidget.talkComboBox.currentIndex() + return self.mainWidget.talkComboBox.model().index(i, 1).data(QtCore.Qt.DisplayRole).toString() + + def standby(self, state): + """Prepares the GStreamer pipelines for recording + + Sets the pipeline to paused state so that initiating a recording + does not have a delay due to GStreamer initialization. + """ + def toggle_gui(state): + """Toggles GUI components when standby is pressed""" + if state: + self.mainWidget.standbyButton.setHidden(state) + self.mainWidget.disengageButton.setVisible(state) + else: + self.mainWidget.disengageButton.setVisible(state) + self.mainWidget.standbyButton.setHidden(state) + + self.mainWidget.recordButton.setEnabled(state) + self.mainWidget.eventComboBox.setDisabled(state) + self.mainWidget.roomComboBox.setDisabled(state) + self.mainWidget.dateComboBox.setDisabled(state) + self.mainWidget.talkComboBox.setDisabled(state) + self.mainWidget.audioFeedbackCheckbox.setDisabled(state) + + if state: # Prepare the pipelines + if self.load_backend(): + toggle_gui(True) + self.controller.pause() + self.mainWidget.statusLabel.setText(u"{} {} --- {} ".format(self.freeSpaceString, + get_free_space(self.config.videodir), + self.readyString)) + else: + toggle_gui(False) + self.mainWidget.standbyButton.setChecked(False) + else: + toggle_gui(False) + self.controller.stop() + self.mainWidget.standbyButton.setChecked(False) + + self.mainWidget.playButton.setEnabled(False) + + def record(self): + """The logic for recording and stopping recording.""" + + if self.mainWidget.is_recording: # Start Recording. + logo_rec = QtGui.QPixmap(":/freeseer/logo_rec.png") + sysIcon2 = QtGui.QIcon(logo_rec) + self.systray.setIcon(sysIcon2) + self.controller.record() + self.mainWidget.recordButton.setToolTip(self.stopString) + self.mainWidget.disengageButton.setEnabled(False) + self.mainWidget.pauseButton.setEnabled(True) + self.recordAction.setText(self.stopString) + + # Hide if auto-hide is set. + if self.config.auto_hide: + self.hide_window() + self.visibilityAction.setText(self.showWindowString) + log.debug('auto-hide is enabled, main window is now hidden in systray.') + + # Start timer. + self.timer.start(1000) + + else: # Stop Recording. + logo_rec = QtGui.QPixmap(":/freeseer/logo.png") + sysIcon = QtGui.QIcon(logo_rec) + self.systray.setIcon(sysIcon) + self.controller.stop() + self.mainWidget.pauseButton.setChecked(False) + self.mainWidget.recordButton.setToolTip(self.recordString) + self.mainWidget.disengageButton.setEnabled(True) + self.mainWidget.pauseButton.setEnabled(False) + self.recordAction.setText(self.recordString) + self.mainWidget.audioSlider.setValue(0) + self.mainWidget.statusLabel.setText(u"{} {} --- {} ".format(self.freeSpaceString, + get_free_space(self.config.videodir), + self.idleString)) + + # Finally set the standby button back to unchecked position. + self.standby(False) + + # Stop and reset timer. + self.timer.stop() + self.reset_timer() + + #Show playback button + self.mainWidget.playButton.setVisible(True) + self.mainWidget.playButton.setEnabled(True) + + # Select next talk if there is one within 15 minutes. + if self.current_event and self.current_room: + starttime = QtCore.QDateTime().currentDateTime() + stoptime = starttime.addSecs(900) + talkid = self.db.get_talk_between_time(self.current_event, self.current_room, + starttime.toString(), stoptime.toString()) + + if talkid is not None: + for i in range(self.mainWidget.talkComboBox.count()): + if talkid == self.mainWidget.talkComboBox.model().index(i, 1).data(QtCore.Qt.DisplayRole).toString(): + self.mainWidget.talkComboBox.setCurrentIndex(i) + + def _enable_disable_gui(self, state): + """Disables GUI components when Auto Record is pressed, and enables them when Auto Record is released""" + self.mainWidget.standbyButton.setDisabled(state) + self.mainWidget.eventComboBox.setDisabled(state) + self.mainWidget.roomComboBox.setDisabled(state) + self.mainWidget.dateComboBox.setDisabled(state) + self.mainWidget.talkComboBox.setDisabled(state) + self.mainWidget.audioFeedbackCheckbox.setDisabled(state) + + def stop_auto_record_gui(self): + """Sets the gui for stopping the auto record""" + self.autoRecordWidget.stop_timer() + self.autoRecordWidget.close() + self._enable_disable_gui(False) + self.recorded = False + self.actionAutoRecord.setChecked(False) + + def auto_record(self, state): + """Starts automated recording""" + if state: + # If there is a room selected, then it's possible to auto-record + if self.current_room: + self.autoTalks = self.db.get_talks_by_room_and_time(self.current_room) + # Start recording if there are talks in database that can be auto-recorded + if self.autoTalks.next(): + # Set the cursor back to before the first record so that single_auto_record works properly + self.autoTalks.previous() + self._enable_disable_gui(True) + self.single_auto_record() + else: + # Dialog for no talks to auto-record + QtGui.QMessageBox.information(self, 'No Talks to Record', + 'There are no upcoming talks to auto-record in this room', QtGui.QMessageBox.Ok) + self.actionAutoRecord.setChecked(False) + + else: + # Dialog that pops up when no room is selected + QtGui.QMessageBox.information(self, 'No Room Selected', + 'Please select a room to auto-record', QtGui.QMessageBox.Ok) + self.actionAutoRecord.setChecked(False) + else: + self.beforeStartTimer.stop() + self.beforeEndTimer.stop() + self.controller.stop() + self.stop_auto_record_gui() + + self.mainWidget.playButton.setEnabled(False) + + def single_auto_record(self): + """Completes one display and record cycle of the auto-record feature. + + Stops the recording of the last talk if it exists, displays the countdown until the start of + the next talk, and when the talk begins, records the talk while displaying the countdown until + the end of the talk. + """ + if self.recorded: + self.controller.stop() + self.recorded = False + log.debug("Auto-recording for the current talk stopped.") + + if self.autoTalks.next(): + starttime = QtCore.QTime.fromString(self.autoTalks.value(8).toString()) + endtime = QtCore.QTime.fromString(self.autoTalks.value(9).toString()) + currenttime = QtCore.QTime.currentTime() + + if currenttime <= starttime: + self.singleID = self.autoTalks.value(0).toString() + title = self.autoTalks.value(1).toString() + speaker = self.autoTalks.value(2).toString() + + # Time (in seconds) until recording for the talk starts + self.timeUntilStart = currenttime.secsTo(starttime) + # Time (in seconds) from the starttime to endtime of this talk + self.timeUntilEnd = starttime.secsTo(endtime) + + # Display fullscreen countdown and talk info until talk starts + self.autoRecordWidget.set_recording(False) + self.autoRecordWidget.set_display_message(title, speaker) + self.autoRecordWidget.start_timer(self.timeUntilStart) + self.autoRecordWidget.showFullScreen() + + # Wait for talk to start, then change display and start recording + self.beforeStartTimer.setInterval((self.timeUntilStart + 1) * 1000) + self.beforeStartTimer.setSingleShot(True) + self.beforeStartTimer.start() + else: + # Start time has already passed, so move on to next talk + self.single_auto_record() + else: + self.stop_auto_record_gui() + + def start_single_record(self): + """Begins the auto-recording of a single talk while displaying the countdown on screen""" + self.autoRecordWidget.set_recording(True) + self.autoRecordWidget.set_display_message() + self.autoRecordWidget.start_timer(self.timeUntilEnd) + if self.controller.record_talk_id(self.singleID): + log.debug("Auto-recording for the current talk started.") + self.recorded = True + self.beforeEndTimer.setInterval((self.timeUntilEnd + 1) * 1000) + self.beforeEndTimer.setSingleShot(True) + self.beforeEndTimer.start() + + def pause(self, state): + """Pause the recording""" + if state: # Pause Recording. + self.controller.pause() + log.info("Recording paused.") + self.mainWidget.pauseButton.setToolTip(self.resumeString) + self.mainWidget.statusLabel.setText(self.pausedString) + self.timer.stop() + elif self.mainWidget.is_recording: + self.controller.record() + log.info("Recording unpaused.") + self.mainWidget.pauseButton.setToolTip(self.pauseString) + self.timer.start(1000) + + def load_backend(self): + """Prepares the backend for recording""" + if self.current_presentation(): + presentation = self.current_presentation() + + # If current presentation is no existant (empty talk database) + # use a default recording name. + else: + presentation = Presentation(title=unicode("default")) + + initialized, self.recently_recorded_video = self.controller.load_backend(presentation) + if initialized: + return True + else: + return False # Error something failed while loading the backend + + def update_timer(self): + """Updates the Elapsed Time displayed. + + Uses the statusLabel for the display. + """ + frmt_time = "%d:%02d" % (self.time_minutes, self.time_seconds) + self.time_seconds += 1 + if self.time_seconds == 60: + self.time_seconds = 0 + self.time_minutes += 1 + + self.mainWidget.statusLabel.setText(u"{} {} --- {} {} --- {}".format(self.elapsedTimeString, + frmt_time, + self.freeSpaceString, + get_free_space(self.config.videodir), + self.recordingString)) + + def reset_timer(self): + """Resets the Elapsed Time.""" + self.time_minutes = 0 + self.time_seconds = 0 + + def toggle_audio_feedback(self, enabled): + """Enables or disables audio feedback according to checkbox state""" + self.config.audio_feedback = enabled + + ### + ### Talk Related + ### + + def set_talk_tooltip(self, talk): + self.mainWidget.talkComboBox.setToolTip(talk) + + def load_event_list(self): + model = self.db.get_events_model() + self.mainWidget.eventComboBox.setModel(model) + + def load_rooms_from_event(self, event): + #self.disconnect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_room) + + self.current_event = event + + model = self.db.get_rooms_model(self.current_event) + self.mainWidget.roomComboBox.setModel(model) + + #self.connect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_room) + + def load_dates_from_event_room(self, change): + event = str(self.mainWidget.eventComboBox.currentText()) + room = str(self.mainWidget.roomComboBox.currentText()) + model = self.db.get_dates_from_event_room_model(event, room) + self.mainWidget.dateComboBox.setModel(model) + + def load_talks_from_date(self, date): + self.current_room = str(self.mainWidget.roomComboBox.currentText()) + self.current_date = date + + model = self.db.get_talks_model(self.current_event, self.current_room, self.current_date) + self.mainWidget.talkComboBox.setModel(model) + + ### + ### Report Failure + ### + def show_report_widget(self): + p = self.current_presentation() + self.reportWidget.titleLabel2.setText(p.title) + self.reportWidget.speakerLabel2.setText(p.speaker) + self.reportWidget.eventLabel2.setText(p.event) + self.reportWidget.roomLabel2.setText(p.room) + self.reportWidget.startTimeLabel2.setText(p.startTime) + self.reportWidget.endTimeLabel2.setText(p.endTime) + + # Get existing report if there is one. + talk_id = self.current_presentation_id() + f = self.db.get_report(talk_id) + if f is not None: + self.reportWidget.commentEdit.setText(f.comment) + i = self.reportWidget.reportCombo.findText(f.indicator) + self.reportWidget.reportCombo.setCurrentIndex(i) + self.reportWidget.releaseCheckBox.setChecked(f.release) + else: + self.reportWidget.commentEdit.setText("") + self.reportWidget.reportCombo.setCurrentIndex(0) + self.reportWidget.releaseCheckBox.setChecked(False) + + self.reportWidget.show() + + def report(self): + talk_id = self.current_presentation_id() + i = self.reportWidget.reportCombo.currentIndex() + + failure = Failure(talk_id, self.reportWidget.commentEdit.text(), self.reportWidget.options[i], self.reportWidget.releaseCheckBox.isChecked()) + log.info("Report Failure: %s, %s, %s, release form? %s" % (talk_id, + self.reportWidget.commentEdit.text(), + self.reportWidget.options[i], + self.reportWidget.releaseCheckBox.isChecked())) + + self.db.insert_failure(failure) + self.reportWidget.close() + + ### + ### Misc. + ### + def _icon_activated(self, reason): + if reason == QtGui.QSystemTrayIcon.Trigger: + self.systray.menu.popup(QCursor.pos()) + if reason == QtGui.QSystemTrayIcon.DoubleClick: + self.toggle_record_button() + + def hide_window(self): + self.geometry = self.saveGeometry() + self.hide() + + def show_window(self): + if (self.geometry is not None): + self.restoreGeometry(self.geometry) + self.show() + + def toggle_window_visibility(self): + """Toggles the visibility of the Recording Main Window.""" + if self.isHidden(): + self.show_window() + self.visibilityAction.setText(self.hideWindowString) + else: + self.hide_window() + self.visibilityAction.setText(self.showWindowString) + + def toggle_record_button(self): + self.mainWidget.standbyButton.toggle() + self.mainWidget.recordButton.toggle() + + def audio_feedback(self, value): + self.mainWidget.audioSlider.setValue(value) + + def open_video_directory(self): + if sys.platform.startswith("linux"): + os.system("xdg-open %s" % self.config.videodir) + elif sys.platform.startswith("win32"): + os.system("explorer %s" % self.config.videodir) + else: + log.info("Error: This command is not supported on the current OS.") + + def closeEvent(self, event): + log.info('Exiting freeseer...') + event.accept() + + ''' + This function plays the most recently recorded video + ''' + def play_video(self): + if sys.platform.startswith("linux"): + subprocess.call(["xdg-open", "{}/{}".format(self.config.videodir, self.recently_recorded_video)]) + if sys.platform.startswith("win32"): + os.system("start {}".format(os.path.join(self.config.videodir, self.recently_recorded_video))) + + ''' + Client functions + ''' + def show_client_widget(self): + self.current_presentation() + self.clientWidget.show() + + ''' + This function is for handling commands sent from the server to the client + ''' + def getAction(self): + message = self.clientWidget.socket.read(self.clientWidget.socket.bytesAvailable()) + if message == 'Record': + self.mainWidget.standbyButton.toggle() + self.mainWidget.recordButton.toggle() + self.clientWidget.sendMessage('Started recording') + log.info("Started recording by server's request") + elif message == 'Stop': + self.mainWidget.recordButton.toggle() + log.info("Stopping recording by server's request") + elif message == 'Pause' or 'Resume': + self.mainWidget.pauseButton.toggle() + if message == 'Pause': + log.info("Paused recording by server's request") + elif message == 'Resume': + log.info("Resumed recording by server's request") + + ### + ### Utility + ### + def open_configtool(self): + self.configToolApp.show() + + def open_talkeditor(self): + self.talkEditorApp.show() + self.load_event_list() diff --git a/src/freeseer/frontend/reporteditor/reporteditor.py b/src/freeseer/frontend/reporteditor/reporteditor.py index 1c14f127..26ec3475 100644 --- a/src/freeseer/frontend/reporteditor/reporteditor.py +++ b/src/freeseer/frontend/reporteditor/reporteditor.py @@ -164,14 +164,14 @@ def add_talk(self): date = self.addTalkWidget.dateEdit.date() startTime = self.addTalkWidget.startTimeEdit.time() datetime = QDateTime(date, startTime) # original "time" is now "startTime" - presentation = Presentation(unicode(self.addTalkWidget.titleLineEdit.text()), - unicode(self.addTalkWidget.presenterLineEdit.text()), + presentation = Presentation(str(self.addTalkWidget.titleLineEdit.text()), + str(self.addTalkWidget.presenterLineEdit.text()), "", # description "", # level - unicode(self.addTalkWidget.eventLineEdit.text()), - unicode(self.addTalkWidget.roomLineEdit.text()), - unicode(datetime.toString()), - unicode(self.addTalkWidget.endTimeEdit.text())) + str(self.addTalkWidget.eventLineEdit.text()), + str(self.addTalkWidget.roomLineEdit.text()), + str(datetime.toString()), + str(self.addTalkWidget.endTimeEdit.text())) # Do not add talks if they are empty strings if (len(presentation.title) == 0): diff --git a/src/freeseer/frontend/talkeditor/talkeditor.py b/src/freeseer/frontend/talkeditor/talkeditor.py index 4f713bb2..e87daa43 100644 --- a/src/freeseer/frontend/talkeditor/talkeditor.py +++ b/src/freeseer/frontend/talkeditor/talkeditor.py @@ -399,18 +399,18 @@ def create_presentation(self, talkDetailsWidget): startTime = talkDetailsWidget.startTimeEdit.time() endTime = talkDetailsWidget.endTimeEdit.time() - title = unicode(talkDetailsWidget.titleLineEdit.text()).strip() + title = str(talkDetailsWidget.titleLineEdit.text()).strip() if title: return Presentation( - unicode(talkDetailsWidget.titleLineEdit.text()).strip(), - unicode(talkDetailsWidget.presenterLineEdit.text()).strip(), - unicode(talkDetailsWidget.descriptionTextEdit.toPlainText()).strip(), - unicode(talkDetailsWidget.categoryLineEdit.text()).strip(), - unicode(talkDetailsWidget.eventLineEdit.text()).strip(), - unicode(talkDetailsWidget.roomLineEdit.text()).strip(), - unicode(date.toString(Qt.ISODate)), - unicode(startTime.toString(Qt.ISODate)), - unicode(endTime.toString(Qt.ISODate))) + str(talkDetailsWidget.titleLineEdit.text()).strip(), + str(talkDetailsWidget.presenterLineEdit.text()).strip(), + str(talkDetailsWidget.descriptionTextEdit.toPlainText()).strip(), + str(talkDetailsWidget.categoryLineEdit.text()).strip(), + str(talkDetailsWidget.eventLineEdit.text()).strip(), + str(talkDetailsWidget.roomLineEdit.text()).strip(), + str(date.toString(Qt.ISODate)), + str(startTime.toString(Qt.ISODate)), + str(endTime.toString(Qt.ISODate))) def show_new_talk_popup(self): """Displays a modal dialog with a talk details view @@ -495,7 +495,7 @@ def confirm_reset(self): self.reset() def add_talks_from_rss(self): - rss_url = unicode(self.importTalksWidget.rssLineEdit.text()) + rss_url = str(self.importTalksWidget.rssLineEdit.text()) if rss_url: self.db.add_talks_from_rss(rss_url) self.presentationModel.select() diff --git a/src/freeseer/frontend/upload/youtube.py b/src/freeseer/frontend/upload/youtube.py index 682b8517..edf6f17c 100644 --- a/src/freeseer/frontend/upload/youtube.py +++ b/src/freeseer/frontend/upload/youtube.py @@ -51,11 +51,11 @@ def get_defaults(): def handle_response(response_code, response): """Process the response from the Youtube API""" if response_code is Response.SUCCESS: - print("The file was successfully uploaded with video id: {}".format(response['id'])) + print(("The file was successfully uploaded with video id: {}".format(response['id']))) elif response_code is Response.UNEXPECTED_FAILURE: - print("The file failed to upload with unexpected response: {}".format(response)) + print(("The file failed to upload with unexpected response: {}".format(response))) elif response_code is Response.UNRETRIABLE_ERROR: - print("An unretriable HTTP error {} occurred:\n{}".format(response['status'], response['content'])) + print(("An unretriable HTTP error {} occurred:\n{}".format(response['status'], response['content']))) elif response_code is Response.MAX_RETRIES_REACHED: print("The maximum number of retries has been reached") elif response_code is Response.ACCESS_TOKEN_ERROR: @@ -88,9 +88,9 @@ def prompt_user(videos, confirmation=False): """ if not confirmation: print("Found videos:") - print("\n".join(videos)) + print(("\n".join(videos))) question = "Are you sure you would like to upload these videos? [Y/n]" - confirmation = raw_input(question).lower() in ('', 'y', 'yes') + confirmation = input(question).lower() in ('', 'y', 'yes') return confirmation @@ -106,7 +106,7 @@ def upload(files, token, assume_yes): """ # check if token exists if not os.path.exists(token): - print("{} does not exist, please specify a valid token file".format(token)) + print(("{} does not exist, please specify a valid token file".format(token))) else: # Gather videos specified and vids from folders specified into list videos = gather_videos(files) diff --git a/src/freeseer/plugins/audioinput/jackaudiosrc/__init__.py b/src/freeseer/plugins/audioinput/jackaudiosrc/__init__.py index 7df368e4..cbeac084 100644 --- a/src/freeseer/plugins/audioinput/jackaudiosrc/__init__.py +++ b/src/freeseer/plugins/audioinput/jackaudiosrc/__init__.py @@ -41,7 +41,7 @@ import freeseer.framework.config.options as options # .freeseer-plugin custom -import widget +from . import widget class JackAudioConfig(Config): diff --git a/src/freeseer/plugins/audioinput/pulsesrc/__init__.py b/src/freeseer/plugins/audioinput/pulsesrc/__init__.py index 1c2e9daf..795701b8 100644 --- a/src/freeseer/plugins/audioinput/pulsesrc/__init__.py +++ b/src/freeseer/plugins/audioinput/pulsesrc/__init__.py @@ -44,7 +44,7 @@ from freeseer.framework.config import Config, options # .freeseer-plugin custom -import widget +from . import widget log = logging.getLogger(__name__) @@ -57,7 +57,7 @@ def get_sources(): audiosrc.probe_property_name('device') names = audiosrc.probe_get_values_name('device') # TODO: should be getting actual device description, but .get_property('device-name') does not work - return zip(names, names) + return list(zip(names, names)) def get_default_source(): diff --git a/src/freeseer/plugins/audiomixer/audiopassthrough/__init__.py b/src/freeseer/plugins/audiomixer/audiopassthrough/__init__.py index 2f62fc26..eaeb7462 100644 --- a/src/freeseer/plugins/audiomixer/audiopassthrough/__init__.py +++ b/src/freeseer/plugins/audiomixer/audiopassthrough/__init__.py @@ -43,7 +43,7 @@ from freeseer.framework.config import Config, options # .freeseer-plugin custom -import widget +from . import widget class AudioPassThroughConfig(Config): diff --git a/src/freeseer/plugins/audiomixer/multiaudio/__init__.py b/src/freeseer/plugins/audiomixer/multiaudio/__init__.py index c13e0123..1eaeecd7 100644 --- a/src/freeseer/plugins/audiomixer/multiaudio/__init__.py +++ b/src/freeseer/plugins/audiomixer/multiaudio/__init__.py @@ -41,7 +41,7 @@ from freeseer.framework.config import Config, options # .freeseer-plugin custom -import widget +from . import widget class MultiAudioConfig(Config): diff --git a/src/freeseer/plugins/importer/csv_importer.py b/src/freeseer/plugins/importer/csv_importer.py index 1c0979d8..48f46830 100644 --- a/src/freeseer/plugins/importer/csv_importer.py +++ b/src/freeseer/plugins/importer/csv_importer.py @@ -57,16 +57,16 @@ def get_presentations(self, fname): reader = csv.DictReader(csv_file) for row in reader: talk = { - 'Title': unicode(row.get('Title', ''), 'utf-8'), - 'Speaker': unicode(row.get('Speaker', ''), 'utf-8'), - 'Abstract': unicode(row.get('Abstract', ''), 'utf-8'), # Description - 'Level': unicode(row.get('Level', ''), 'utf-8'), - 'Event': unicode(row.get('Event', ''), 'utf-8'), - 'Room': unicode(row.get('Room', ''), 'utf-8'), - 'Time': unicode(row.get('Time', ''), 'utf-8'), # Legacy csv time field - 'Date': unicode(row.get('Date', ''), 'utf-8'), - 'StartTime': unicode(row.get('StartTime', ''), 'utf-8'), - 'EndTime': unicode(row.get('EndTime', ''), 'utf-8') + 'Title': str(row.get('Title', ''), 'utf-8'), + 'Speaker': str(row.get('Speaker', ''), 'utf-8'), + 'Abstract': str(row.get('Abstract', ''), 'utf-8'), # Description + 'Level': str(row.get('Level', ''), 'utf-8'), + 'Event': str(row.get('Event', ''), 'utf-8'), + 'Room': str(row.get('Room', ''), 'utf-8'), + 'Time': str(row.get('Time', ''), 'utf-8'), # Legacy csv time field + 'Date': str(row.get('Date', ''), 'utf-8'), + 'StartTime': str(row.get('StartTime', ''), 'utf-8'), + 'EndTime': str(row.get('EndTime', ''), 'utf-8') } presentations.append(talk) diff --git a/src/freeseer/plugins/importer/rss_feedparser/__init__.py b/src/freeseer/plugins/importer/rss_feedparser/__init__.py index a7be8001..a660c711 100644 --- a/src/freeseer/plugins/importer/rss_feedparser/__init__.py +++ b/src/freeseer/plugins/importer/rss_feedparser/__init__.py @@ -34,7 +34,7 @@ try: # Import Python3 module if possible from html.parser import HTMLParser except ImportError: - from HTMLParser import HTMLParser + from html.parser import HTMLParser from feedparser import parse @@ -87,7 +87,7 @@ def get_presentations(self, feed_url): # data contain spaces and we don't want to erroneously split that # data. - pres_data = filter(None, pres_data.split(" ")) + pres_data = [_f for _f in pres_data.split(" ") if _f] presentation = { 'Title': entry.title.strip(), @@ -116,6 +116,6 @@ def get_presentation_field(self, presentation, field_name): # data in element is in unicode, we want an error raised if # there are characters that we are not expecting - field_data = unicode(presentation[i + item_presentation_offset]) + field_data = str(presentation[i + item_presentation_offset]) return strip_tags(field_data).strip() diff --git a/src/freeseer/plugins/output/audiofeedback/__init__.py b/src/freeseer/plugins/output/audiofeedback/__init__.py index f72c592a..900ef42f 100644 --- a/src/freeseer/plugins/output/audiofeedback/__init__.py +++ b/src/freeseer/plugins/output/audiofeedback/__init__.py @@ -42,7 +42,7 @@ from freeseer.framework.config import Config, options # .freeseer-plugin -import widget +from . import widget class AudioFeedbackConfig(Config): diff --git a/src/freeseer/plugins/output/ogg_icecast/__init__.py b/src/freeseer/plugins/output/ogg_icecast/__init__.py index ed6fcb45..474e0c92 100644 --- a/src/freeseer/plugins/output/ogg_icecast/__init__.py +++ b/src/freeseer/plugins/output/ogg_icecast/__init__.py @@ -42,7 +42,7 @@ from freeseer.framework.config import Config, options # .freeseer-plugin custom -import widget +from . import widget class OggIcecastConfig(Config): @@ -152,7 +152,7 @@ def set_metadata(self, data): ''' self.tags = gst.TagList() - for tag in data.keys(): + for tag in list(data.keys()): if(gst.tag_exists(tag)): self.tags[tag] = data[tag] else: diff --git a/src/freeseer/plugins/output/ogg_output/__init__.py b/src/freeseer/plugins/output/ogg_output/__init__.py index 7e2b4e76..252be1d9 100644 --- a/src/freeseer/plugins/output/ogg_output/__init__.py +++ b/src/freeseer/plugins/output/ogg_output/__init__.py @@ -43,7 +43,7 @@ from freeseer.framework.config import Config, options # .freeseer-plugin custom -import widget +from . import widget class OggOutputConfig(Config): @@ -157,7 +157,7 @@ def set_metadata(self, data): ''' self.tags = gst.TagList() - for tag in data.keys(): + for tag in list(data.keys()): if(gst.tag_exists(tag)): self.tags[tag] = data[tag] else: diff --git a/src/freeseer/plugins/output/rtmp_streaming/__init__.py b/src/freeseer/plugins/output/rtmp_streaming/__init__.py index 5536e3bc..3da34942 100644 --- a/src/freeseer/plugins/output/rtmp_streaming/__init__.py +++ b/src/freeseer/plugins/output/rtmp_streaming/__init__.py @@ -104,7 +104,7 @@ # for freeseer to run. # try: - import httplib + import http.client import simplejson from oauth import oauth except: @@ -275,7 +275,7 @@ def set_metadata(self, data): ''' self.tags = gst.TagList() - for tag in data.keys(): + for tag in list(data.keys()): if(gst.tag_exists(tag)): self.tags[tag] = data[tag] else: @@ -690,7 +690,7 @@ def open_request(consumer_key, consumer_secret): request.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(), consumer, None) - connection = httplib.HTTPConnection(JustinApi.addr) + connection = http.client.HTTPConnection(JustinApi.addr) connection.request('GET', request.http_url, headers=request.to_header()) result = connection.getresponse().read() @@ -739,7 +739,7 @@ def obtain_access_token(self): http_method='GET', http_url=url) request.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(), consumer, token) - connection = httplib.HTTPConnection(self.addr) + connection = http.client.HTTPConnection(self.addr) connection.request('GET', request.http_url, headers=request.to_header()) result = connection.getresponse().read() self.access_token_str = result @@ -758,11 +758,12 @@ def get_data(self, endpoint): http_method='GET', http_url="http://%s/api/%s" % (JustinApi.addr, endpoint)) request.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(), consumer, token) - connection = httplib.HTTPConnection(self.addr) + connection = http.client.HTTPConnection(self.addr) connection.request('GET', request.http_url, headers=request.to_header()) result = connection.getresponse().read() data = simplejson.loads(result) - except KeyError, simplejson.decoder.JSONDecodeError: + except KeyError as xxx_todo_changeme: + simplejson.decoder.JSONDecodeError = xxx_todo_changeme log.error("justin.tv API: failed fetch data from endpoint %s" % endpoint) return dict() return data @@ -778,7 +779,7 @@ def set_data(self, endpoint, payload): http_url="http://%s/api/%s" % (JustinApi.addr, endpoint), parameters=payload) request.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(), consumer, token) - connection = httplib.HTTPConnection(self.addr) + connection = http.client.HTTPConnection(self.addr) connection.request('POST', request.http_url, body=request.to_postdata()) result = connection.getresponse().read() except KeyError: diff --git a/src/freeseer/plugins/output/videopreview/__init__.py b/src/freeseer/plugins/output/videopreview/__init__.py index 8fa2e232..d03dc4ef 100644 --- a/src/freeseer/plugins/output/videopreview/__init__.py +++ b/src/freeseer/plugins/output/videopreview/__init__.py @@ -42,7 +42,7 @@ from freeseer.framework.config import Config, options # .freeseer-plugin custom -import widget +from . import widget # Leaky Queue LEAKY_VALUES = ["no", "upstream", "downstream"] diff --git a/src/freeseer/plugins/output/webm_output/__init__.py b/src/freeseer/plugins/output/webm_output/__init__.py index 63e0b847..cdac93bc 100644 --- a/src/freeseer/plugins/output/webm_output/__init__.py +++ b/src/freeseer/plugins/output/webm_output/__init__.py @@ -132,7 +132,7 @@ def set_metadata(self, data): ''' self.tags = gst.TagList() - for tag in data.keys(): + for tag in list(data.keys()): if(gst.tag_exists(tag)): self.tags[tag] = data[tag] else: diff --git a/src/freeseer/plugins/videoinput/desktop/__init__.py b/src/freeseer/plugins/videoinput/desktop/__init__.py index a08eb878..0f43acca 100644 --- a/src/freeseer/plugins/videoinput/desktop/__init__.py +++ b/src/freeseer/plugins/videoinput/desktop/__init__.py @@ -46,7 +46,7 @@ from freeseer.framework.config import Config, options # .freeseer-plugin custom modules -import widget +from . import widget log = logging.getLogger(__name__) diff --git a/src/freeseer/plugins/videoinput/firewiresrc/__init__.py b/src/freeseer/plugins/videoinput/firewiresrc/__init__.py index 2d41d9f4..a26329c2 100644 --- a/src/freeseer/plugins/videoinput/firewiresrc/__init__.py +++ b/src/freeseer/plugins/videoinput/firewiresrc/__init__.py @@ -45,7 +45,7 @@ from freeseer.framework.config import Config, options # .freeseer-plugin custom modules -import widget +from . import widget def detect_devices(): diff --git a/src/freeseer/plugins/videoinput/usbsrc/__init__.py b/src/freeseer/plugins/videoinput/usbsrc/__init__.py index 9e3e7132..f82d2d7f 100644 --- a/src/freeseer/plugins/videoinput/usbsrc/__init__.py +++ b/src/freeseer/plugins/videoinput/usbsrc/__init__.py @@ -44,7 +44,7 @@ from freeseer.framework.config import Config, options # .freeseer-plugin custom modules -import widget +from . import widget def get_devices(): @@ -90,7 +90,7 @@ def get_default_device(): devicemap = get_devices() if not devicemap: return '' - default = devicemap.itervalues().next() + default = next(iter(devicemap.values())) return default @@ -152,7 +152,7 @@ def widget_load_config(self, plugman): # Load the combobox with inputs self.widget.devicesCombobox.clear() n = 0 - for device, devurl in get_devices().items(): + for device, devurl in list(get_devices().items()): self.widget.devicesCombobox.addItem(device, devurl) if devurl == self.config.device: self.widget.devicesCombobox.setCurrentIndex(n) diff --git a/src/freeseer/plugins/videoinput/videotestsrc/__init__.py b/src/freeseer/plugins/videoinput/videotestsrc/__init__.py index ec1572aa..426e00d5 100644 --- a/src/freeseer/plugins/videoinput/videotestsrc/__init__.py +++ b/src/freeseer/plugins/videoinput/videotestsrc/__init__.py @@ -42,7 +42,7 @@ from freeseer.framework.config import Config, options # .freeseer-plugin custom modules -import widget +from . import widget # Patterns PATTERNS = ["smpte", "snow", "black", "white", "red", "green", "blue", diff --git a/src/freeseer/plugins/videomixer/pip/__init__.py b/src/freeseer/plugins/videomixer/pip/__init__.py index 34453e5d..12d0c75a 100644 --- a/src/freeseer/plugins/videomixer/pip/__init__.py +++ b/src/freeseer/plugins/videomixer/pip/__init__.py @@ -42,7 +42,7 @@ from freeseer.framework.config import Config, options # .freeseer-plugin custom modules -import widget +from . import widget class PictureInPictureConfig(Config): @@ -122,7 +122,7 @@ def load_inputs(self, player, mixer, inputs): mainsrc_elements = [input1, mainsrc_scale, mainsrc_capsfilter, mainsrc_colorspace] # Add elements to player in list order - map(lambda element: player.add(element), mainsrc_elements) + list(map(lambda element: player.add(element), mainsrc_elements)) # Link elements in a specific order input1.link(mainsrc_scale) @@ -147,7 +147,7 @@ def load_inputs(self, player, mixer, inputs): pipsrc_elements = [input2, pipsrc_scale, pipsrc_capsfilter, pipsrc_colorspace] #Add elements to player in list order - map(lambda element: player.add(element), pipsrc_elements) + list(map(lambda element: player.add(element), pipsrc_elements)) # Link elements in specific order input2.link(pipsrc_scale) diff --git a/src/freeseer/plugins/videomixer/videopassthrough/__init__.py b/src/freeseer/plugins/videomixer/videopassthrough/__init__.py index dedfeaeb..cb00a6bc 100644 --- a/src/freeseer/plugins/videomixer/videopassthrough/__init__.py +++ b/src/freeseer/plugins/videomixer/videopassthrough/__init__.py @@ -44,7 +44,7 @@ from freeseer.framework.config import Config, options # .freeseer-plugin custom modules -import widget +from . import widget log = logging.getLogger(__name__) @@ -54,7 +54,7 @@ class VideoPassthroughConfig(Config): input = options.StringOption("Video Test Source") input_type = options.StringOption("video/x-raw-rgb") framerate = options.IntegerOption(30) - resolution = options.ChoiceOption(widget.resmap.keys(), "No Scaling") + resolution = options.ChoiceOption(list(widget.resmap.keys()), "No Scaling") class VideoPassthrough(IVideoMixer): diff --git a/src/freeseer/tests/framework/config/options/test_choice.py b/src/freeseer/tests/framework/config/options/test_choice.py index 5b26650a..139aac79 100644 --- a/src/freeseer/tests/framework/config/options/test_choice.py +++ b/src/freeseer/tests/framework/config/options/test_choice.py @@ -44,9 +44,9 @@ class TestChoiceOptionNoDefault(unittest.TestCase, OptionTest): 'w0rld', ] - encode_success = zip(valid_success, valid_success) + encode_success = list(zip(valid_success, valid_success)) - decode_success = zip(valid_success, valid_success) + decode_success = list(zip(valid_success, valid_success)) decode_failure = valid_failure def setUp(self): diff --git a/src/freeseer/tests/framework/config/options/test_float.py b/src/freeseer/tests/framework/config/options/test_float.py index 54ba660f..0544c594 100644 --- a/src/freeseer/tests/framework/config/options/test_float.py +++ b/src/freeseer/tests/framework/config/options/test_float.py @@ -34,11 +34,11 @@ class TestFloatOptionNoDefault(unittest.TestCase, OptionTest): """Tests FloatOption without a default value.""" - valid_success = [x / 10.0 for x in xrange(-100, 100)] + valid_success = [x / 10.0 for x in range(-100, 100)] - encode_success = zip(valid_success, map(str, valid_success)) + encode_success = list(zip(valid_success, list(map(str, valid_success)))) - decode_success = zip(map(str, valid_success), valid_success) + decode_success = list(zip(list(map(str, valid_success)), valid_success)) decode_failure = [ 'hello', '1world', diff --git a/src/freeseer/tests/framework/config/options/test_folder.py b/src/freeseer/tests/framework/config/options/test_folder.py index 7dbc540d..5927c40e 100644 --- a/src/freeseer/tests/framework/config/options/test_folder.py +++ b/src/freeseer/tests/framework/config/options/test_folder.py @@ -44,9 +44,9 @@ class TestFolderOptionNoDefault(unittest.TestCase, OptionTest): '/tmp/1', ] - encode_success = zip(valid_success, valid_success) + encode_success = list(zip(valid_success, valid_success)) - decode_success = zip(valid_success, valid_success) + decode_success = list(zip(valid_success, valid_success)) decode_failure = valid_failure def setUp(self): diff --git a/src/freeseer/tests/framework/config/options/test_integer.py b/src/freeseer/tests/framework/config/options/test_integer.py index 237efd33..adf3c672 100644 --- a/src/freeseer/tests/framework/config/options/test_integer.py +++ b/src/freeseer/tests/framework/config/options/test_integer.py @@ -34,11 +34,11 @@ class TestIntegerOptionNoDefault(unittest.TestCase, OptionTest): """Tests IntegerOption without a default value.""" - valid_success = range(-1000, 1000) + valid_success = list(range(-1000, 1000)) - encode_success = zip(valid_success, map(str, valid_success)) + encode_success = list(zip(valid_success, list(map(str, valid_success)))) - decode_success = zip(map(str, valid_success), valid_success) + decode_success = list(zip(list(map(str, valid_success)), valid_success)) decode_failure = [ 'hello', '1world', diff --git a/src/freeseer/tests/framework/test_multimedia.py b/src/freeseer/tests/framework/test_multimedia.py index eed754ac..1afced12 100644 --- a/src/freeseer/tests/framework/test_multimedia.py +++ b/src/freeseer/tests/framework/test_multimedia.py @@ -52,10 +52,10 @@ def tearDown(self): shutil.rmtree(self.profile_manager._base_folder) def test_load_backend(self): - self.multimedia.load_backend(filename=u"test.ogg") + self.multimedia.load_backend(filename="test.ogg") def test_record_functions(self): - self.multimedia.load_backend(filename=u"test.ogg") + self.multimedia.load_backend(filename="test.ogg") self.multimedia.record() self.multimedia.pause() self.multimedia.stop() diff --git a/src/freeseer/tests/framework/test_presentation.py b/src/freeseer/tests/framework/test_presentation.py index 5d882254..3b365961 100644 --- a/src/freeseer/tests/framework/test_presentation.py +++ b/src/freeseer/tests/framework/test_presentation.py @@ -51,7 +51,7 @@ def test_correct_time_set(self): self.assertTrue(self.pres.endTime == "Later") def test_speaker_not_first_param(self): - self.assertNotEquals(self.pres.speaker, "John Doe") + self.assertNotEqual(self.pres.speaker, "John Doe") def test_event_is_default(self): self.assertTrue(self.pres.event == "haha") diff --git a/src/freeseer/tests/framework/test_youtube.py b/src/freeseer/tests/framework/test_youtube.py index 2a7f3cd9..0816b16e 100644 --- a/src/freeseer/tests/framework/test_youtube.py +++ b/src/freeseer/tests/framework/test_youtube.py @@ -41,7 +41,7 @@ class TestYoutubeService(unittest.TestCase): ], 'categoryId': 27, 'description': 'At Test by Alex recorded on 2014-03-09', - 'title': u'Test', + 'title': 'Test', } def test_get_metadata(self): diff --git a/src/freeseer/tests/frontend/configtool/test_config_tool.py b/src/freeseer/tests/frontend/configtool/test_config_tool.py index 0665dafc..7c242c23 100644 --- a/src/freeseer/tests/frontend/configtool/test_config_tool.py +++ b/src/freeseer/tests/frontend/configtool/test_config_tool.py @@ -88,13 +88,13 @@ def check_combobox_corner_cases_frontend(self, combobox_widget): """ index = combobox_widget.currentIndex() combobox_widget.setCurrentIndex(0) - self.assertEquals(combobox_widget.currentIndex(), 0) + self.assertEqual(combobox_widget.currentIndex(), 0) self.assertIsNot(combobox_widget.currentText(), None) combobox_widget.setCurrentIndex(combobox_widget.count() - 1) - self.assertEquals(combobox_widget.currentIndex(), (combobox_widget.count() - 1)) + self.assertEqual(combobox_widget.currentIndex(), (combobox_widget.count() - 1)) self.assertIsNot(combobox_widget.currentText(), None) combobox_widget.setCurrentIndex(index) - self.assertEquals(combobox_widget.currentIndex(), index) + self.assertEqual(combobox_widget.currentIndex(), index) self.assertIsNot(combobox_widget.currentText(), None) def select_general_settings_tab(self): @@ -320,12 +320,12 @@ def test_plugin_settings(self): QtTest.QTest.keyClick(self.config_tool.pluginWidget.list, QtCore.Qt.Key_Down) # Assert expected categories exist. - self.assertIn('AudioInput', plugin_category.values()) - self.assertIn('AudioMixer', plugin_category.values()) - self.assertIn('VideoInput', plugin_category.values()) - self.assertIn('VideoMixer', plugin_category.values()) - self.assertIn('Output', plugin_category.values()) - self.assertIn('Importer', plugin_category.values()) + self.assertIn('AudioInput', list(plugin_category.values())) + self.assertIn('AudioMixer', list(plugin_category.values())) + self.assertIn('VideoInput', list(plugin_category.values())) + self.assertIn('VideoMixer', list(plugin_category.values())) + self.assertIn('Output', list(plugin_category.values())) + self.assertIn('Importer', list(plugin_category.values())) for category in ['AudioInput', 'AudioMixer', 'VideoInput', 'VideoMixer', 'Output', 'Importer']: for plugin in self.config_tool.get_plugins(category): diff --git a/src/freeseer/tests/frontend/configtool/test_config_tool.py.bak b/src/freeseer/tests/frontend/configtool/test_config_tool.py.bak new file mode 100644 index 00000000..e69de29b diff --git a/src/freeseer/tests/frontend/controller/test_server.py b/src/freeseer/tests/frontend/controller/test_server.py index ff4102f8..cc790133 100644 --- a/src/freeseer/tests/frontend/controller/test_server.py +++ b/src/freeseer/tests/frontend/controller/test_server.py @@ -274,7 +274,7 @@ def test_post(self, test_client, recording): assert len(recording.media_dict) == 0 response = test_client.post('/recordings', data={'filename': 'test'}) assert response.status_code == 201 - assert recording.media_dict.keys() == [1] + assert list(recording.media_dict.keys()) == [1] assert recording.media_info['1']['filename'] == 'test.ogg' def test_delete_no_recording_id(self, test_client): @@ -311,7 +311,7 @@ def test_delete_in_progress_recording(self, test_client, recording, mock_media_d response = test_client.delete('/recordings/1') assert response.status_code == 204 assert del_media.num_times_stop_called == 1 - assert recording.media_dict.keys() == [2] + assert list(recording.media_dict.keys()) == [2] def test_delete_recording_id_and_file(self, test_client, recording, mock_media_dict): ''' @@ -333,7 +333,7 @@ def test_delete_recording_id_and_file(self, test_client, recording, mock_media_d response = test_client.delete('/recordings/1') assert response.status_code == 204 - assert recording.media_dict.keys() == [2] + assert list(recording.media_dict.keys()) == [2] # assert the file no longer exists assert not os.path.isfile(file_to_delete_path) diff --git a/src/freeseer/tests/frontend/controller/test_server.py.bak b/src/freeseer/tests/frontend/controller/test_server.py.bak new file mode 100644 index 00000000..e69de29b diff --git a/src/freeseer/tests/frontend/test_cli_talk.py b/src/freeseer/tests/frontend/test_cli_talk.py index eaa9142a..6cb03fec 100644 --- a/src/freeseer/tests/frontend/test_cli_talk.py +++ b/src/freeseer/tests/frontend/test_cli_talk.py @@ -63,16 +63,16 @@ def test_add_talk(self, mock_profile): sys.argv[1:] = args cli.parse_args(self.parser, args) talks = self.db.get_talks() - talks.next() # Point to talk data - talks.next() # Skip default blank entry - talks.next() # Skip first test entry - talks.next() # Skip second test entry + next(talks) # Point to talk data + next(talks) # Skip default blank entry + next(talks) # Skip first test entry + next(talks) # Skip second test entry record = talks.record() - self.assertEqual(talks.value(record.indexOf('title')).toString(), u'test title') - self.assertEqual(talks.value(record.indexOf('speaker')).toString(), u'john doe') - self.assertEqual(talks.value(record.indexOf('event')).toString(), u'testing') - self.assertEqual(talks.value(record.indexOf('room')).toString(), u'rm123') + self.assertEqual(talks.value(record.indexOf('title')).toString(), 'test title') + self.assertEqual(talks.value(record.indexOf('speaker')).toString(), 'john doe') + self.assertEqual(talks.value(record.indexOf('event')).toString(), 'testing') + self.assertEqual(talks.value(record.indexOf('room')).toString(), 'rm123') def test_remove_talk(self): """Test removing a talk""" diff --git a/src/freeseer/tests/frontend/upload/test_youtube.py b/src/freeseer/tests/frontend/upload/test_youtube.py index f8b9a3d4..1185186a 100644 --- a/src/freeseer/tests/frontend/upload/test_youtube.py +++ b/src/freeseer/tests/frontend/upload/test_youtube.py @@ -26,7 +26,7 @@ import sys import unittest import pytest -from StringIO import StringIO +from io import StringIO from freeseer.framework.youtube import Response from freeseer.frontend.upload import youtube