Guido Draheim avatar Guido Draheim committed 395c51b Merge

merge with trunk

Comments (0)

Files changed (14)

 all: builds install restart
 upd up: rpm update restart
 
+
+msg msgchk:
+	python setup.py copy_catalog
+	python setup.py extract_messages
+	python setup.py update_catalog
+	python setup.py compile_catalog
+	grep -B 2 'msgstr.*""' */*/*/LC_MESSAGES/*.po | sed -e 's/^--$$//'
 msgfmt:
 	python setup.py copy_catalog
 	python setup.py compile_catalog
 	   
 trac restart:
 	sudo /sbin/service tracd restart
+
+OSC_ROOT = /my/own/osc
+OSC_PROJECT = home:guidod:trac12
+OSC_PACKAGE = trac-dvbcronrecording-plugin
+OSC = $(OSC_ROOT)/$(OSC_PROJECT)/$(OSC_PACKAGE)
+osc: dist
+	@ version=`cat $(SPECNAME).spec | sed -e '/define _version/!d' -e 's/.*_version //'` \
+	; tarball="$(RPMROOT)/SOURCES/$(PKG)-$$version.tgz" \
+	; specpath="$(RPMROOT)/SPECS/$(SPECNAME).spec" \
+	; if [ -f "$$tarball" ]; then set -x \
+	;    (cd $(OSC) && osc rm *.tgz) \
+	;    cp -v "$$tarball" $(OSC)/ \
+	;    (cd $(OSC) && osc add `basename "$$tarball"` \
+	;    cp -v "$$specpath" $(OSC)/$(SPECNAME).spec \
+	;    (cd $(OSC) && osc ci -m "update $$version") \
+	; else : \
+	;    echo "failed to find $$tarball" \
+	; fi	  
+
+.PHONY: osc trac restart update install dist sdist msgfmt
+
+	

src/dvbcronrecording/computer.py

     from channels import DvbCronRecordingChannelsPlugin
 except:
     DvbCronRecordingChannelsPlugin = None
+    
+from translate import Translate
 
 DEBUG = False
 PACKAGE = 'dvbcronrecording'
         return item
     def __unicode__(self):
         return u"(%s) '%s'" % (unicode(self.months), unicode(self.title))
+    def __str__(self):
+        return unicode(self).encode("UTF-8")
     
 class RecorderGroup:
     def __init__(self):
             self.endtimeMMM = orig.endtimeMMM
             self.extratimeM = orig.extratimeM
         return self
+    def __unicode__(self):
+        return u"[%s - %s] %s" % (self.datetimeX, self.datetimeY, unicode(self.item))
+    def __str__(self):
+        return unicode(self).encode("UTF-8")
 
 months_ahead = 3
     
                 ranges += [ (months[0],months[0])]
             item.cronmonths = ranges
         return group
-    def plan1(self, entries):
+    def plan1(self, req, entries):
         """ main entry point """
         plan = RecorderGroupPlan()
         for group in self.recordinglist_to_recordergroups(entries):
         for item in itemlist:
             if item.newtimeMMM == item.endtimeMMM:
                 yield item
-    def plan2(self, entries):
+    def plan2(self, req, entries):
         """ main entry point """
         itemlist = list(self.recordinglist_to_flat_recorderitems(entries))
         deleted = 0
                         yield elem
                 except:
                     pass
-    def adjust_recordertimelist(self, recordertimelist, adapter = None):
+    def adjust_recordertimelist(self, req, recordertimelist, adapter = None):
         """ recordertimelist contains absolute X Y dates """
+        _ = Translate(PACKAGE, req.locale)
         minimum = datetime.timedelta(minutes = 2)
         previous = None
         for current in recordertimelist:
             if previous.datetimeY <= current.datetimeX:
                 previous = current
                 continue # nothing to do - there is a gap
-            if previous.datetimeX > current.datetimeX:
-                raise Exception("previous starts after current")
             overlapY = previous.datetimeY - current.datetimeX
             overlapM = deltaM(overlapY)
             assert overlapM > 0
             if previous.item.rank < current.item.rank:
+                if previous.datetimeX > current.datetimeX:
+                    if previous.datetimeY < current.datetimeY:
+                        # previous is fully inside the current times -> delete
+                        previous.message += _(" deleted as moved inside")
+                        previous.datetimeY = previous.datetimeX
+                        previous.newtimeMMM = previous.endtimeMMM
+                        previous.extratimeM = 0
+                        previous.deleted = True
+                        previous = current
+                        continue
+                    else:
+                        msg = (u"previous starts after current\nPREV %s\nNEXT %s" 
+                               % (previous, current))
+                        raise Exception(msg)                        
                 # move previous endtime down
                 if overlapM <= previous.extratimeM:
                     previous.extratimeM -= overlapM
                     previous.datetimeY -= overlapY
                     if current.item.channelname != previous.item.channelname:
-                        previous.message += " cut extratimeM %03d," % overlapM
+                        previous.message += _(" extra minutes minus %03d,") % overlapM
                     else:
-                        previous.message += " continues"
+                        previous.message += _(" continues")
                     previous = current
                 else: 
                     extraY = datetime.timedelta(minutes = previous.extratimeM)
                         previous.datetimeY = previous.datetimeX
                         previous.endtimeMMM = previous.newtimeMMM
                         previous.extratimeM = 0
-                        previous.message += " deleted as next one starts %s," % MMMtoHHMM(current.newtimeMMM)
+                        previous.message += _(" deleted as next one starts %s,") % MMMtoHHMM(current.newtimeMMM)
                     else:
                         if previous.datetimeY > current.datetimeX:
                             previous.datetimeY = current.datetimeX
                             previous.endtimeMMM = current.newtimeMMM
                             if current.item.channelname != previous.item.channelname:
-                                previous.message += " end time set to next start %s," % MMMtoHHMM(current.newtimeMMM)
+                                previous.message += _(" end time set to next start %s,") % MMMtoHHMM(current.newtimeMMM)
                             else:
-                                previous.message += " continue"
+                                previous.message += _(" continues")
                         if previous.datetimeY - previous.datetimeX < minimum:
                             previous.deleted = True
                             previous.datetimeY = previous.datetimeX
                             previous.endtimeMMM = previous.newtimeMMM
                             previous.extratimeM = 0
-                            previous.message += " and deleted as it is too short now"
+                            previous.message += _(" and deleted as it is too short now")
                         else:
                             previous = current
-            else:
-                # move current starttime up
+            else: # previous.item.rank >= current.item.rank
+                # ..move current starttime up
+                if previous.datetimeX > current.datetimeX:
+                    if previous.datetimeX >= current.datetimeY:
+                        msg = (u"previous starts after current\nPREV %s\nNEXT %s" 
+                               % (previous, current))
+                        raise Exception(msg)
+                    else:
+                        current.datetimeX = previous.datetimeX
+                        current.newtimeMMM = previous.endtimeMMM
+                        current.message += _(" set start time to previous start %s,") % MMMtoHHMM(current.newtimeMMM)
+                        assert previous.datetimeY > current.datetimeX
                 if current.datetimeY <= previous.datetimeY:
                     if previous.datetimeX > current.datetimeX:
-                        current.message+= "previous starts after current"
+                        current.message+= _(" previous starts after current")
                     current.deleted = True
                     current.datetimeX = current.datetimeY
                     current.newtimeMMM = current.endtimeMMM
                     current.extratimeM = 0
-                    current.message += " deleted as previous one ends %s," % MMMtoHHMM(previous.endtimeMMM)
+                    current.message += _(" deleted as previous one ends %s,") % MMMtoHHMM(previous.endtimeMMM)
                 else:
                     if current.datetimeX < previous.datetimeY:
                         current.datetimeX = previous.datetimeY
                         #    current.item.months = [ current.datetimeX.month ] 
                         current.newtimeMMM = previous.endtimeMMM + previous.extratimeM
                         if current.item.channelname != previous.item.channelname:
-                            current.message += " set start time to previous end %s," % MMMtoHHMM(current.newtimeMMM)
+                            current.message += _(" set start time to previous end %s,") % MMMtoHHMM(current.newtimeMMM)
                         else:
-                            current.message += " continue"
+                            current.message += _(" continues")
                     if current.datetimeY - current.datetimeX < minimum:
                         current.deleted = True
                         current.datetimeX = current.datetimeY
                         current.newtimeMMM = current.endtimeMMM
                         current.extratimeM = 0
-                        current.message += " and deleted as it is too short now"
+                        current.message += _(" and deleted as it is too short now")
                     else:
                         previous = current
     def assign_adapters_for_timelist(self, recordertimelist):
             if previous.datetimeY <= current.datetimeX:
                 previous = current
                 continue # nothing to do - there is a gap
-            if previous.datetimeX > current.datetimeX:
-                raise Exception("previous starts after current")
             overlapY = previous.datetimeY - current.datetimeX
             overlapM = deltaM(overlapY)
             assert overlapM > 0
             if not done:
                 # can not split overlapping recordings to different adapers
                 pass
-    def timelist_groups(self, timelist, adapter = None):
+    def timelist_groups(self, req, timelist, adapter = None):
+        _ = Translate(PACKAGE, req.locale)
         group = None
         previous = None
         previousgroup = None
                     yield group ; previousgroup = group; group = None
                 item.message = " ."+item.message
                 if elem.deleted: 
-                    item.message += " [DEL]"
+                    item.message += _(" [DEL]")
                     predeletes += [ item ]
                 else:
                     previous = elem
                 # HANDOVER
                 item.message = " :"+item.message
                 if elem.deleted: 
-                    item.message += " [DEL]"
+                    item.message += _(" [DEL]")
                     group.items += [ item ]
                 else:
                     previous = elem
             if group.deleted: continue
             newplan.addgroup(group)
         return newplan
-    def plan3(self, entries):
+    def plan3(self, req, entries):
         """ main entry point """
         self.logg.info("plan3")
         timelist = list(self.recordinglist_to_recordertimelist(entries))
         old_deleted = 0
         for round in xrange(2):
             timelist = sorted(timelist, key = lambda x: x.datetimeX )
-            self.adjust_recordertimelist(timelist)
+            self.adjust_recordertimelist(req, timelist)
             deleted = [ elem for elem in timelist if elem.deleted ]
             new_deleted = len(deleted)
             if old_deleted < new_deleted:
                 continue
         timelist = sorted(timelist, key = lambda x: x.datetimeX )
         plan = RecorderGroupPlan()
-        for group in self.timelist_groups(timelist):
+        for group in self.timelist_groups(req, timelist):
             plan.addgroup(group)
         if True:
             return self.new_reduce_regular_groups(plan)
         if True:
             return self.reduce_regular_groups(plan)
         return plan
-    def plan4(self, entries):
+    def plan4(self, req, entries):
         """ main entry point """
         self.logg.info("plan4")
         timelist = list(self.recordinglist_to_recordertimelist(entries))
         for round in xrange(2):
             timelist = sorted(timelist, key = lambda x: x.datetimeX )
             for adapter in self.adapterlist():
-                self.adjust_recordertimelist(timelist, adapter)
+                self.adjust_recordertimelist(req, timelist, adapter)
             deleted = [ elem for elem in timelist if elem.deleted ]
             new_deleted = len(deleted)
             if old_deleted < new_deleted:
         timelist = sorted(timelist, key = lambda x: x.datetimeX )
         plan = RecorderGroupPlan()
         for adapter in self.adapterlist():
-            for group in self.timelist_groups(timelist, adapter):
+            for group in self.timelist_groups(req, timelist, adapter):
                 plan.addgroup(group)
         self.logg.info("adapterlist = %s", self.adapterlist())
         if True:
             plan.timelist_sort()
             return plan
             
-    def plan(self, entries):
+    def plan(self, req, entries):
         if self.algorithm == "plan1":
-            return self.plan1(entries)
+            return self.plan1(req, entries)
         if self.algorithm == "plan2":
-            return self.plan2(entries)
+            return self.plan2(req, entries)
         self.set_adapters_from_channels_list(self.channels_list())
         if self.algorithm == "plan3":
-            return self.plan3(entries)
+            return self.plan3(req, entries)
         if self.algorithm == "plan4":
-            return self.plan4(entries)
+            return self.plan4(req, entries)
         #else:
-        return self.plan4(entries)
+        return self.plan4(req, entries)
 
 def deltaM(td):
     return td.seconds / 60 + (td.days * 24 * 60)

src/dvbcronrecording/core.py

 import re
 import os.path
 import time
+import datetime
 import locale
 
 from trac.core import Component, implements
 from trac.web import IRequestHandler
 from trac.perm import IPermissionRequestor
 from trac.web.chrome import INavigationContributor, ITemplateProvider
+from trac.timeline.api import ITimelineEventProvider
 from trac.config import Option, ListOption, PathOption, BoolOption
 
 from translate import Translate #@UnresolvedImport
 
 from dvbcronrecording.db.session import db_cnx, commit
 from dvbcronrecording.db.schema import RecordingList #@UnresolvedImport
+from dvbcronrecording.db.schema import RecordingChanges #@UnresolvedImport
 
 def _(text): return text
 
     #
 
     implements(IPermissionRequestor, INavigationContributor, ITemplateProvider,
-      IRequestHandler)
+      IRequestHandler, ITimelineEventProvider)
 
     vardir = Option(PACKAGE, "vardir", VARDIR, 
      doc="Where to store the runtime data like the makefile and cronfile.")
             add_script(req, 'common/js/trac.js')
             return ('recordingplan.html', data, None)
         if page in [ 'activate' ]:
-            data = {}
-            data['title'] = translate("Cron Activate")
-            makefile_entries = self._makefile_entries(req)
-            makefile_list = [ entry.rule for entry in makefile_entries  ]
-            makefile_entries = self._makefile_entries(req) # FIXME
-            crontab_lines = self._to_crontablines(makefile_entries)
-            crontab_reload = self.crontabreloadline()
-            crontab_change = self.crontabchangeline()
-            crontab_list = list(crontab_lines)
-            written_messages = []
-            for adapter in self.adapter_list(req):
-                filename = self.cron_channelsconf_filename(adapter)
-                conf = self.channelsconf_for_adapter(adapter)
-                if conf:
-                    written = self.writefile(req, filename, conf)
-                    written_messages += [ written ]
-            a = self.writefile(req, self.cronfilename(), list(crontab_list))
-            b = self.writefile(req, self.makefilename(), list(makefile_list))
-            c = self.writefile(req, self.cron_update_filename(), [ crontab_reload ])
-            d = self.writefile(req, self.cron_update_change_filename(), [ crontab_change ])
-            e = translate("cron.will.be.updated.every")+(" %s" % self.cronminutes_string())
-            if self.crondirectly:
-                e = self.writefile(req, self.cron_target_filename(), list(crontab_list))
-            data['messages'] = written_messages + [ a, b, c, d, e ]
-            data['cronlines'] = crontab_list # + [ " ============= "] + makefile_list
-            data['_'] = translate
-            add_stylesheet(req, PACKAGE+'/css/recordinglist.css')
-            add_stylesheet(req, PACKAGE+'/css/dvbcronrecording.css')
-            add_script(req, 'common/js/trac.js')
-            return ('recordingcronfile.html', data, None)
+            return self._activate(req, page)
         if page in [ "save" ]:
             text = req.args["text"]
             result = self.savetext(req, text)
         # passing variables to template
         data = {}
         data['message'] = message
-        data['title'] = translate('Recordings List')
+        data['title'] = translate('Recording List')
         data['recordings'] = self._recordings_list(req)
         data['appends'] = req.perm.has_permission(LIST_APPEND);
         data['author'] = req.authname or ""
         add_script(req, 'common/js/wikitoolbar.js')
         return ('recordinglist.html', data, None)
 
+    # ITimelineEventProvider methods
+
+    def get_timeline_filters(self, req):
+        filters = []
+        if LIST_VIEW in req.perm:
+            filters += [ ("recordinglist", _("Recording List"), False)]
+        return filters
+
+    def get_timeline_events(self, req, start, stop, filters):
+        try:
+            if "recordinglist" in filters:
+                session = db_cnx(self.env)
+                q = session.query(RecordingChanges)
+                q = q.filter(RecordingChanges.modified >= start)
+                q = q.filter(RecordingChanges.modified <= stop)
+                for item in q.all():
+                    yield (PACKAGE, item.modified.replace(tzinfo=req.tz), item.username,
+                           (item.tablename, item.changed))
+        except Exception, e:
+                yield (PACKAGE, datetime.datetime.now(), req.authname,
+                       "ERROR:%s" % str(e))
+            
+    def render_timeline_event(self, context, field, event):
+        tablename, changed = event[3]
+        if field == 'url':
+            return context.href.recording('list')
+        elif field == 'title':
+            gettext = Translate(PACKAGE, context.req.locale)
+            if changed.startswith("ACTIVATE"):
+                title = gettext("the recording list was activated")
+            else:
+                title = gettext("a recording list entry was modified")
+            return title
+        elif field == 'description':
+            translate = Translate(PACKAGE, context.req.locale)
+            gettext = translate
+            mapped = {"set next recording on" : gettext("set next recording on"),
+                      "set some recording on" : gettext("set some recording on"),                      
+                      "set no recording on" : gettext("set no recording on"),
+                      "ACTIVATE: the modified recordinglist was activated":
+                        gettext("ACTIVATE: the modified recordinglist was activated")
+                      }
+            for a,b in mapped.items():
+                if changed.startswith(a):
+                    changed = b + changed[len(a):]
+            for i, name in translate("**weekdaynames").items():
+                changed = changed.replace(("**%s]" % i), (name+"]"))
+            return changed
+        
+            
     # ====================================================================
     
     # ====================================================================
         item.title = req.args.get("title")
         session = db_cnx(self.env)
         session.add(item)
+        datespec = "[%s-%s%s]" % (item.newtime, 
+                                item.endtime, 
+                                item.onlydate and " "+item.onlydate or " **%s" % item.weekday 
+                               ) 
+        changed = "new recording on %s %s %s" % (item.channelname,
+                                                 datespec,
+                                                 item.title)
+        session.add(RecordingChanges(tablename="RecordingList",
+                                  username=req.authname,
+                                  modified=datetime.datetime.now(),
+                                  changed=changed))
         session.flush()
         return u"OK [rec:%s]" % item.id
 
         item.status = req.args.get("status")
         item.priority = req.args.get("priority")
         item.title = req.args.get("title")
+        state = item.status
+        if state == "ok": state = "next"
+        if not state: state = "some"
+        datespec = "[%s-%s%s]" % (item.newtime, 
+                                item.endtime, 
+                                item.onlydate and " "+item.onlydate or " **%s" % item.weekday 
+                               ) 
+        changed = "set %s recording on %s %s %s" % (state,
+                                                         item.channelname,
+                                                         datespec,
+                                                         item.title)
+        session.add(RecordingChanges(tablename="RecordingList",
+                                  username=req.authname,
+                                  modified=datetime.datetime.now(),
+                                  changed=changed))
         session.flush()
         return u"OK [rec:%s]" % item.id
 
     def loadtextlines(self, req):
         entries = self._recordings_list(req)
         computer = DvbCronRecordingPlanComputer(self.env)
-        plan = computer.plan(entries)
+        plan = computer.plan(req, entries)
         for group in plan.groups():
             newtime = MMMtoHHMM(group.newtimeMMM).replace(":","")
             weekday = group.weekday
     # ---------------------------------------------------------------
     # chain up the entries
     # ---------------------------------------------------------------
+    def _activate(self, req, page):
+        req.perm.assert_permission(LIST_VIEW)
+        translate = Translate(PACKAGE, req.locale, req.languages )
+        data = {}
+        data['title'] = translate("Cron Activate")
+        makefile_entries = self._makefile_entries(req)
+        makefile_list = [ entry.rule for entry in makefile_entries  ]
+        makefile_entries = self._makefile_entries(req) # FIXME
+        crontab_lines = self._to_crontablines(makefile_entries)
+        crontab_reload = self.crontabreloadline()
+        crontab_change = self.crontabchangeline()
+        crontab_list = list(crontab_lines)
+        written_messages = []
+        for adapter in self.adapter_list(req):
+            filename = self.cron_channelsconf_filename(adapter)
+            conf = self.channelsconf_for_adapter(adapter)
+            if conf:
+                written = self.writefile(req, filename, conf)
+                written_messages += [ written ]
+        a = self.writefile(req, self.cronfilename(), list(crontab_list))
+        b = self.writefile(req, self.makefilename(), list(makefile_list))
+        c = self.writefile(req, self.cron_update_filename(), [ crontab_reload ])
+        d = self.writefile(req, self.cron_update_change_filename(), [ crontab_change ])
+        e = translate("cron.will.be.updated.every")+(" %s" % self.cronminutes_string())
+        if self.crondirectly:
+            e = self.writefile(req, self.cron_target_filename(), list(crontab_list))
+        try:
+            message = "ACTIVATE: the modified recordinglist was activated"
+            session = db_cnx(self.env)
+            session.add(RecordingChanges(tablename="RecordingList",
+                                  username=req.authname,
+                                  modified=datetime.datetime.now(),
+                                  changed=message))
+        except:
+            pass
+        data['messages'] = written_messages + [ a, b, c, d, e ]
+        data['cronlines'] = crontab_list # + [ " ============= "] + makefile_list
+        data['_'] = translate
+        add_stylesheet(req, PACKAGE+'/css/recordinglist.css')
+        add_stylesheet(req, PACKAGE+'/css/dvbcronrecording.css')
+        add_script(req, 'common/js/trac.js')
+        return ('recordingcronfile.html', data, None)
+    
     def _recording_plan(self, req):
         entries = self._recordings_list(req)
-        return list(self._recording_plan_from(entries))
-    def _recording_plan_from(self, entries):
+        return list(self._recording_plan_from(req, entries))
+    def _recording_plan_from(self, req, entries):
         computer = DvbCronRecordingPlanComputer(self.env)
-        plan = computer.plan(entries)
+        plan = computer.plan(req, entries)
         for item in plan.items():
             yield item
             
     def _makefile_entries(self, req):
         entries = self._recordings_list(req)
         computer = DvbCronRecordingPlanComputer(self.env)
-        plan = computer.plan(entries)
+        plan = computer.plan(req, entries)
         adapterlist = AdapterList()
         for group in plan.groups():
             if not group.items: continue

src/dvbcronrecording/db/schema.py

 RecordingChannels = _db.RecordingChannels
 RecordingChannelsConf = _db.RecordingChannelsConf
 RecordingList = _db.RecordingList
+RecordingChanges = _db.RecordingChanges
 
 pass

src/dvbcronrecording/dvbcronrecording.de.po

 msgstr "Recorder-Liste"
 
 msgid "recording list"
-msgstr "Recorder-Liste"
+msgstr "Aufnahmeliste"
 
 msgid "activate!"
 msgstr "Aktivieren!"
 msgid "channels.conf editor"
 msgstr "channels.conf Editor"
 
+msgid "channels.conf text"
+msgstr "channels.conf Text"
+
+msgid "channels.conf edit"
+msgstr "channels.conf Edit"
+
+msgid "channels.conf list"
+msgstr "channels.conf Liste"
+
 #  channels.de.po
 
 msgid "insert"
 msgstr "Startzeit"
 
 msgid "ends"
-msgstr "Endzeit"
+msgstr "Ende"
 
 msgid "extra"
 msgstr "Extra"
 msgstr "Startzeit"
 
 msgid "endtime"
-msgstr "Endzeit"
+msgstr "Endet"
 
 msgid "hint"
 msgstr "Hinweis"
 msgid "Cron Activate"
 msgstr "Cron Aktivierung"
 
-msgid "Recordings List"
-msgstr "Die Recorder-Liste"
+msgid "Recording List"
+msgstr "Die Aufnahmeliste"
 
 
 # ---------------------------------------------------------
 msgid "input 0:0 for <adapter>:<frontend>"
 msgstr "Eingabe 0:0 meint <Adapter>:<Frontend>"
 
+msgid "Download"
+msgstr "Herunterladen"
+
+# time adjustment computer ...
+msgid " extra minutes minus %03d,"
+msgstr " Extraminuten minus %03d"
+
+#, python-format
+msgid " deleted as next one starts %s,"
+msgstr " gelöscht denn nächste Aufnahme startet %s,"
+
+#, python-format
+msgid " end time set to next start %s,"
+msgstr " Schlusszeit gesetzt auf nächste Startzeit %s"
+
+#
+msgid " and deleted as it is too short now"
+msgstr " gelöscht denn die Aufnahme ist nun zu kurz"
+
+#
+msgid " previous starts after current"
+msgstr " vorherige Aufnahme startet nach aktueller"
+
+#, python-format
+msgid " deleted as previous one ends %s,"
+msgstr " gelöscht denn vorige Aufnahme endet %s"
+
+#, python-format
+msgid " set start time to previous end %s,"
+msgstr " Startzeit gesetzt auf vorige Schlusszeit %s"
+
+#
+msgid " [DEL]"
+msgstr " [ENTF]"
+
+msgid " continues"
+msgstr " weiterlaufend"
+
+msgid "the recording list was activated"
+msgstr "Die Aufnahmeliste wurde aktiviert"
+
+msgid "a recording list entry was modified"
+msgstr "Ein Aufnahmeeintrag wurde verändert"
+ 
+msgid "set next recording on"
+msgstr "Setzte nächste Aufnahme auf"
+
+msgid "set some recording on"
+msgstr "Setzte eine Aufnahme auf"
+
+msgid "set no recording on"
+msgstr "Ohne Aufnahme gesetzt auf"
+
+msgid "ACTIVATE: the modified recordinglist was activated"
+msgstr "AKTIVIERT: die veränderte Aufnahmelist wurde aktiviert"
+
+msgid " deleted as moved inside"
+msgstr " gelöscht da nun innerhalb"
+
+msgid "  set start time to previous start %s,"
+msgstr " Startzeit gesetzt auf vorige Startzeit %s,"

src/dvbcronrecording/locale/dvbcronrecording.pot

+#: dvbcronrecording/computer.py:696
+#, python-format
+msgid " extra minutes minus %03d,"
+msgstr ""
+
+#: dvbcronrecording/computer.py:698 dvbcronrecording/computer.py:717
+#: dvbcronrecording/computer.py:747
+msgid " continues"
+msgstr ""
+
+#: dvbcronrecording/computer.py:709
+#, python-format
+msgid " deleted as next one starts %s,"
+msgstr ""
+
+#: dvbcronrecording/computer.py:715
+#, python-format
+msgid " end time set to next start %s,"
+msgstr ""
+
+#: dvbcronrecording/computer.py:723 dvbcronrecording/computer.py:753
+msgid " and deleted as it is too short now"
+msgstr ""
+
+#: dvbcronrecording/computer.py:730
+msgid " previous starts after current"
+msgstr ""
+
+#: dvbcronrecording/computer.py:735
+#, python-format
+msgid " deleted as previous one ends %s,"
+msgstr ""
+
+#: dvbcronrecording/computer.py:745
+#, python-format
+msgid " set start time to previous end %s,"
+msgstr ""
+
+#: dvbcronrecording/computer.py:837 dvbcronrecording/computer.py:855
+msgid " [DEL]"
+msgstr ""
+
+#: dvbcronrecording/core.py:297
+msgid "Recording List"
+msgstr ""
+
+#: dvbcronrecording/core.py:321
+msgid "the recording list was activated"
+msgstr ""
+
+#: dvbcronrecording/core.py:323
+msgid "a recording list entry was modified"
+msgstr ""
+
+#: dvbcronrecording/core.py:328
+msgid "set next recording on"
+msgstr ""
+
+#: dvbcronrecording/core.py:329
+msgid "set some recording on"
+msgstr ""
+
+#: dvbcronrecording/core.py:330
+msgid "set no recording on"
+msgstr ""
+
+#: dvbcronrecording/core.py:332
+msgid "ACTIVATE: the modified recordinglist was activated"
+msgstr ""
+
+#: dvbcronrecording/templates/channels_list.html:30
+#: dvbcronrecording/templates/channels_text.html:29
+msgid "channels.conf text"
+msgstr ""
+
+#: dvbcronrecording/templates/channels_list.html:43
+#: dvbcronrecording/templates/channelsconf_take.html:88
+#: dvbcronrecording/templates/recordingplan.html:30
+msgid "channelname"
+msgstr ""
+
+#: dvbcronrecording/templates/channels_list.html:44
+#: dvbcronrecording/templates/channelsconf_editor.html:50
+#: dvbcronrecording/templates/channelsconf_list.html:56
+#: dvbcronrecording/templates/channelsconf_take.html:48
+#: dvbcronrecording/templates/tuninglist.html:26
+msgid "adapter"
+msgstr ""
+
+#: dvbcronrecording/templates/channels_list.html:45
+msgid "channel.conf title"
+msgstr ""
+
+#: dvbcronrecording/templates/channels_list.html:46
+#: dvbcronrecording/templates/channelsconf_list.html:65
+#: dvbcronrecording/templates/tuninglist.html:29
+msgid "action buttons"
+msgstr ""
+
+#: dvbcronrecording/templates/channels_list.html:53
+#: dvbcronrecording/templates/channelsconf_list.html:74
+#: dvbcronrecording/templates/recordinglist.html:43
+#: dvbcronrecording/templates/tuninglist.html:36
+msgid "NEW"
+msgstr ""
+
+#: dvbcronrecording/templates/channels_list.html:66
+#: dvbcronrecording/templates/channelsconf_list.html:99
+#: dvbcronrecording/templates/recordinglist.html:77
+#: dvbcronrecording/templates/tuninglist.html:41
+msgid "insert"
+msgstr ""
+
+#: dvbcronrecording/templates/channels_list.html:98
+#: dvbcronrecording/templates/channelsconf_list.html:146
+#: dvbcronrecording/templates/recordinglist.html:143
+#: dvbcronrecording/templates/tuninglist.html:80
+msgid "update"
+msgstr ""
+
+#: dvbcronrecording/templates/channels_nav.html:2
+msgid "recording list"
+msgstr ""
+
+#: dvbcronrecording/templates/channels_nav.html:3
+msgid "channel list"
+msgstr ""
+
+#: dvbcronrecording/templates/channels_nav.html:4
+msgid "show recorded files"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_editor.html:29
+#: dvbcronrecording/templates/channelsconf_take.html:30
+msgid "channels.conf list"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_editor.html:39
+#: dvbcronrecording/templates/channelsconf_take.html:40
+msgid "channels.conf edit"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_list.html:30
+msgid "channel subselection"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_list.html:31
+msgid "channel type"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_list.html:48
+msgid "channels.conf editor"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_list.html:57
+#: dvbcronrecording/templates/channelsconf_take.html:49
+#: dvbcronrecording/templates/recordingplan.html:31
+msgid "title"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_list.html:58
+#: dvbcronrecording/templates/channelsconf_take.html:50
+msgid "frequency"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_list.html:59
+#: dvbcronrecording/templates/channelsconf_take.html:51
+msgid "polarity"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_list.html:60
+#: dvbcronrecording/templates/channelsconf_take.html:52
+msgid "source"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_list.html:61
+#: dvbcronrecording/templates/channelsconf_take.html:53
+msgid "symbolrate"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_list.html:62
+#: dvbcronrecording/templates/channelsconf_take.html:54
+msgid "vpid"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_list.html:63
+#: dvbcronrecording/templates/channelsconf_take.html:55
+msgid "apid"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_list.html:64
+#: dvbcronrecording/templates/channelsconf_take.html:56
+msgid "tpid"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_list.html:151
+#: dvbcronrecording/templates/channelsconf_take.html:94
+msgid "takeover"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_nav.html:2
+msgid "video channels"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_nav.html:3
+msgid "radio channels"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_nav.html:4
+msgid "channel.conf show"
+msgstr ""
+
+#: dvbcronrecording/templates/channelsconf_nav.html:5
+msgid "tuning list"
+msgstr ""
+
+#: dvbcronrecording/templates/paginator_datalist.html:5
+msgid "Pages:"
+msgstr ""
+
+#: dvbcronrecording/templates/paginator_datalist.html:14
+msgid "shown"
+msgstr ""
+
+#: dvbcronrecording/templates/paginator_datalist.html:18
+msgid " of "
+msgstr ""
+
+#: dvbcronrecording/templates/paginator_datalist.html:23
+msgid "entries"
+msgstr ""
+
+#: dvbcronrecording/templates/paginator_datalist.html:26
+#, python-format
+msgid "%(n)s entry"
+msgid_plural "%(n)s entries"
+msgstr[0] ""
+msgstr[1] ""
+
+#: dvbcronrecording/templates/recording_nav.html:2
+msgid "activate!"
+msgstr ""
+
+#: dvbcronrecording/templates/recording_nav.html:3
+msgid "makefile"
+msgstr ""
+
+#: dvbcronrecording/templates/recording_nav.html:4
+msgid "cronfile"
+msgstr ""
+
+#: dvbcronrecording/templates/recording_nav.html:5
+msgid "edit as text"
+msgstr ""
+
+#: dvbcronrecording/templates/recording_nav.html:6
+msgid "recording plan"
+msgstr ""
+
+#: dvbcronrecording/templates/recordingfiles.html:27
+msgid "Download"
+msgstr ""
+
+#: dvbcronrecording/templates/recordingfiles.html:40
+msgid "time"
+msgstr ""
+
+#: dvbcronrecording/templates/recordingfiles.html:41
+msgid "size"
+msgstr ""
+
+#: dvbcronrecording/templates/recordingfiles.html:42
+msgid "name"
+msgstr ""
+
+#: dvbcronrecording/templates/recordingfiles.html:43
+#: dvbcronrecording/templates/recordingfiles.html:73
+msgid "play"
+msgstr ""
+
+#: dvbcronrecording/templates/recordingfiles.html:78
+msgid "mplay"
+msgstr ""
+
+#: dvbcronrecording/templates/recordinglist.html:26
+msgid "channel"
+msgstr ""
+
+#: dvbcronrecording/templates/recordinglist.html:27
+msgid "starts"
+msgstr ""
+
+#: dvbcronrecording/templates/recordinglist.html:28
+msgid "ends"
+msgstr ""
+
+#: dvbcronrecording/templates/recordinglist.html:29
+msgid "extra"
+msgstr ""
+
+#: dvbcronrecording/templates/recordinglist.html:30
+#: dvbcronrecording/templates/recordingplan.html:25
+msgid "weekday"
+msgstr ""
+
+#: dvbcronrecording/templates/recordinglist.html:31
+#: dvbcronrecording/templates/recordingplan.html:26
+msgid "onlydate"
+msgstr ""
+
+#: dvbcronrecording/templates/recordinglist.html:32
+msgid "status"
+msgstr ""
+
+#: dvbcronrecording/templates/recordinglist.html:32
+msgid "prio"
+msgstr ""
+
+#: dvbcronrecording/templates/recordingplan.html:27
+msgid "newtime"
+msgstr ""
+
+#: dvbcronrecording/templates/recordingplan.html:28
+msgid "endtime"
+msgstr ""
+
+#: dvbcronrecording/templates/recordingplan.html:32
+msgid "hint"
+msgstr ""
+
+#: dvbcronrecording/templates/tuninglist.html:27
+msgid "transponder"
+msgstr ""
+
+#: dvbcronrecording/templates/tuninglist.html:28
+msgid "scansettings"
+msgstr ""
+
+#: dvbcronrecording/templates/tuninglist.html:44
+#: dvbcronrecording/templates/tuninglist.html:85
+msgid "from"
+msgstr ""
+
+#: dvbcronrecording/templates/tuninglist.html:46
+#: dvbcronrecording/templates/tuninglist.html:87
+msgid "satellite"
+msgstr ""
+
+#: dvbcronrecording/templates/tuninglist.html:51
+#: dvbcronrecording/templates/tuninglist.html:92
+msgid "related"
+msgstr ""
+
+#: dvbcronrecording/templates/tuninglist.html:53
+#: dvbcronrecording/templates/tuninglist.html:94
+msgid "as the original channels.conf"
+msgstr ""
+

src/dvbcronrecording/templates/channels_list.html

 
 		<table cellpadding="0" cellspacing="0">
 			<tr>
-				<th>x</th>
+				<th>&nbsp;</th>
 				<th class="id">#</th>
 				<th class="channelname">${_('channelname')}&nbsp;</th>
 				<th class="adapter">${_('adapter')}&nbsp;</th>

src/dvbcronrecording/templates/channelsconf_editor.html

                         ${adapter1}
                 </option>
             </select>
-            <input type="submit" value="${_('channel.conf list')}" class="actionbutton"></input>
+            <input type="submit" value="${_('channels.conf list')}" class="actionbutton"></input>
           </form>
           <form method="get" action="${href.recording('channelsconf/edit')}" class="actionform">
             <select name="adapter">

src/dvbcronrecording/templates/channelsconf_take.html

                         ${adapter1}
                 </option>
             </select>
-            <input type="submit" value="${_('channel.conf list')}" class="actionbutton"></input>
+            <input type="submit" value="${_('channels.conf list')}" class="actionbutton"></input>
           </form>
           <form method="get" action="${href.recording('channelsconf/edit')}" class="actionform">
             <select name="adapter">

src/dvbcronrecording/templates/recordingfiles.html

      <object height="${videoheight}" width="${videowidth}" type="${videotype}" 
                data="${href.recording('file/data/'+videofile)}">
        <div class="alternative">
-         Download 
+         ${_("Download")} 
          <a href="${href.recording('file/data/'+videofile)}">
                 ${href.recording('file/data/'+videofile)}
          </a>

src/dvbcronrecording/templates/tuninglist.html

 
   <table cellpadding="0" cellspacing="0">
         <tr>
-      <th>x</th>
+      <th>&nbsp;</th>
       <th class="id">#</th>
       <th class="adapter">${_('adapter')}&nbsp;</th>
       <th class="transponder">${_('transponder')}&nbsp;</th>

src/dvbcronrecording/translate.py

         trans = self.get(msg)
         if kwargs: return trans % kwargs
         return trans
+    def gettext(self, msg):
+        return self.get(msg)
     def get(self, msg, default = None):
         trans = self.t.ugettext(msg)
         if trans in [ msg ] and default is not None: return default
 # input_file
 # statistics
 
-[extract_dvbcronrecording]
+[extract_messages]
 add_comments = TRANSLATORS:
 output_file = dvbcronrecording/locale/dvbcronrecording.pot
 width = 80
-statistics = true
+omit_header = true
 
 [init_catalog]
 domain = dvbcronrecording
 input_file = dvbcronrecording/locale/dvbcronrecording.pot
 output_dir = dvbcronrecording/locale
 previous = true
+no_fuzzy_matching = true
 
 [copy_catalog]
 output_dir = dvbcronrecording/locale

src/trac-dvbcronrecording-plugin.spec

 # norootforbuild
-%define _version 0.4.16
+%define _version 0.4.17
 %define _name DvbCronRecording
 %define _pkg dvbcronrecording
 %{!?revision: %define revision 0 }
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.