~ubuntu-branches/ubuntu/precise/mythtv/precise

« back to all changes in this revision

Viewing changes to mythplugins/mytharchive/mythburn/scripts/mythburn.py

  • Committer: Package Import Robot
  • Author(s): Mario Limonciello
  • Date: 2012-03-05 21:49:35 UTC
  • mfrom: (1.1.78)
  • Revision ID: package-import@ubuntu.com-20120305214935-vxn0sv24s35dl1sw
Tags: 2:0.25.0~master.20120305.6519666-0ubuntu1
* Drop mythtv-themes metapackage and childish theme.  Should be installed
  exclusively through theme chooser now.
* Update Mythbuntu theme git links to still create that theme package.
* Update configure without install patch.
* Tweak default max_connections for mysql to be 100 per requests from
  mythtv mailing lists.
* Update to a checkout post mythtv 0.25 beta release.
* New upstream checkout (6519666)
* >>Upstream changes since last upload (532cee8):
* [6519666] Use deleteLater() when deleting server sockets in
  ServerPool.
* [b08b41b] Silence unused variable warning
* [5112e25] Silence unused variable warning
* [40c69e1] AvFormatDecoder: add FORCE_DTS_TIMESTAMPS environment
  variable
* [dbb5ffb] Merge branches 'master' and 'master' of
  github.com:MythTV/mythtv
* [57687c8] Subtitles: Initialize the SRT error count to avoid bogus
  diagnostics.
* [6c3a799] Increase kMaxUIWaitTime to 10 seconds. The theory is that
  this timeout was to prevent a very delayed response to an
  availability check causing playlists to resume playing long after
  the user had moved on. The present timeout was very short though and
  didn't account for delays caused by disks needing to be spun up or
  just the latency of checking multiple storage groups for a file.
  Almost certainly fixes #8316
* [dd9a92a] Subtitles: Fix a null pointer dereference when splitting
  long lines.
* [5f98ce1] Fixes #10367. Adds new Motorolla DCX-3200 vendor and
  device id.
* [7347bf5] Fix for WSDL generation.
* [a454b79] Allow the processing of uncompressed data from Schedules
  Direct.
* [f19c9c2] Minor changes to allow compilation using VS2010
* [0607b58] Fix build after [6a200130eff4]
* [6a20013] Handle more ISO-639 codes
* [d1a6cc8] Fix universal package build with new osx-builder
* [20f2c45] Fix UPnP for Sony BluRay players
* [638192e] mythtranscode: --fifoinfo reports aspect ratio of first
  uncut frame
* [18fdd67] Look in more than one location for libdvdcss on mac.
* [871a1cd] Giving up on Qt, doing it with an external command.
* [4392c16] Delay first call to QTextCodec until after main
  QApplication has been created
* [da7626e] Do not disable mythmusic dependencies when using --
  disable-all
* [ca996e0] Updated Norwegian Bokmal MythFrontend and all plugins
  translation from Rune Evjen.
* [18ab21a] Rearrange code in AddRangeList to defeat compile warnings
* [2422b6f] Miscellaneous string fixes
* [5e898a1] Fix HLS AddVideoLiveStream with files in subdirectories.
* [f834940] MythArchive: Remove the Cancel options from the menus
* [366d96d] Correct issue passing python library name for dependency
  checking.
* [c09418f] MythBrowser: Remove the Cancel options from the menus
* [002d7c5] MythMusic: Remove the Cancel options from the menus
* [bb3d1a8] MythMusic: Add some context menus on the playlist editor
  screen
* [bf4ff78] Per 2075458f5 Remove deprecated attribute from
  dispatchNow(), we know it's deprecated but it's not going away any
  time soon
* [12bbcf0] Fix a warning about an unused variable in httpconfig.cpp
* [43dcfce] Fix a warning about an unused variable in videolist.cpp
* [4edcda6] Move the Recording Profiles editor into mythtv-setup where
  it belongs. This constantly gets overlooked because it's not in the
  right place, especially by users who chose to use a third party
  frontend.
* [d7c8dfb] Better default device (when MediaMonitor disabled) on OS
  X. Refs #10370
* [7b526c4] Rework AudioReencodeBuffer further to fix HLS audio
  buffering
* [a130e74] Bump ABI version.
* [5e976b4] Rename util.h into mythmiscutil.h
* [efe385c] Fix dcraw detection on FreeBSD (old sh, not bash)
* [f5aa5e8] Use QNetworkAddressEntry to get proper broadcast address
  for udplistener
* [b6f9e1d] Revert "Rename util.h into mythutil.h"
* [84275f1] Revert "util.h rename itself didn't get committed"
* [8ef8c0b] Merge branch 'master' of github.com:MythTV/mythtv
* [0fe6e14] Totally rework the AudioReencodeBuffer part in transcode
* [fb8004a] util.h rename itself didn't get committed
* [ef771da] Rename util.h into mythutil.h
* [ba9b5d3] Rewrite configure for mythplugins
* [a5557a3] Fix MythZoneMinder on mac; the proper way..
* [30ed8f0] DeleteMap tracker: Fix an error in 94d27c67f.
* [6ae9f66] Rewrite configure for mythplugins
* [0fc9853] Fix MythZoneMinder on mac; the proper way..
* [79f5133] Updated US English MythFrontend and all plugins
  translation from the US English Language Translation Team.
* [6952dc4] Miscellaneous typo and case fixes.
* [b85f5bb] MythArchive: various minor mythburn.py script improvements
* [7e9cd56] Missed a change from cda7871f - I forgot to make install
  when testing and missed the breakage.
* [9d83307] Remove an errant <value> tag from the mythgallery default
  theme. This was causing some confusion for translators.
* [cda7871] Fix the channel icon not loading in the OSD on remote
  frontends by switching to using the channel icon storage group. This
  bug has been around for years so it's nice to finally have a fix.
* [e0e321f] Additional case and spacing fixes.
* [47c7c48] Add a few missing spaces...
* [736524b] Various case and punctuation fixes.
* [eba28f4] MythMusic: Only abort ripping upon confirmation
* [81acf24] Tweak the space available for the channel number so that
  it remains hidden behind the poster.
* [fbba2ae] Show coverart in the Terra OSD, falling back to channel
  icon if the artwork isn't available and channel number if the
  channel icon isn't available.
* [ff4d601] DVD navigation: Reenable skipping past the last chapter of
  a title, and skipping previous to the first chapter of a title.  The
  limitation may have been left over from an older version of
  libdvdnav.
* [8ea557a] Fix 'depends'. I'm surprised I didn't notice this earlier,
  perhaps because I was using <group> a lot I missed that depends
  behaviour didn't work for immediate children of <window>.
* [eb87f9e] Fix 'depends' for inherited and copied screens.
* [38221b8] Only show poster in the default-wide OSD when we're not
  displaying the channum/icon/callsign. Also center the poster better
  in the available space.
* [69cae58] Merge commit 'e965387441ff189bb2c096f8ed5bdbf2b2a473e6'
* [e965387] Add setup script and readme
* [905e8e5] Split 'mythtv/bindings/python/MythTV/tmdb3/' into commit
  '565041dddf9d4937c31c0d57475c548e56882e89'
* [565041d] Enable search paging for TMDB v3 API.
* [367b05d] Enable search paging for TMDB v3 API.
* [6113151] Add proper language support to TMDB v3 API.
* [6410395] Add proper language support to TMDB v3 API.
* [c65d8eb] Remove TMDB API key from request.py
* [6c4c60a] Remove TMDB API key from request.py
* [b38f901] Fix some null strings in SQL inserts on NOT NULL columns.
* [55fd3bf] MythUI: Make ascent/descent/bearing adjustment a little
  easier to follow, by using moveTop/moveLeft instead of setX/setY
* [d16575c] MythUI: fix a typo in MythUIText::DrawSelf that could
  result in an incorrect canvas size.
* [64383c5] Fix a compiler warning.
* [ecea05d] Added ENO to an error log in avformatdecoder
* [03e2387] Services API: Fix cut and paste error.
* [99abdfe] Update xml schema declaration for 0.25
* [6e2f231] Fix typo
* [05e5cf7] Updated Spanish/Spain MythFrontend, MythArchive,
  MythBrowser, MythGallery, MythGame, MythMusic, MythNetvision,
  MythNews, MythWeather transation from the Spanish Language
  Translation Team
* [2f895cb] Fix mythzoneminder on mac part #3
* [e34c8d7] Fix universal architecture compilation of myth on mac.
* [a513779] Fix MythZoneMinder part #2
* [700a58d] Remove stray include, same as <Qt>
* [d84d5c9] Add basic dead key support to mythuitextedit. Implemented
  from scratch because I couldn't see a way of getting QT to handle
  it. 
* [c3544ed] Fix mac compilation
* [6bfda0c] Fix mythoneminder compilation when using mysql universal
  libraries.
* [21ad34b] Add --firewire-sdk configuration switch to configure
* [3196c2c] Fix FireWire compilation on mac when compiling in 64 bits
  mode.
* [5dccbd5] Fix mac compilation when Qt Frameworks are in use.
* [20d6852] Fix libcec configure to work with v1.5
* [f16048b] Finish the db upgrade to 1299 (perl bindings)
* [d486b8a] Make artwork edit UI elements optional on video metadata
  edit screen.
* [38dfa89] Updated British English MythFrontend, MythArchive,
  MythGame and MythMusic translation from Nick Morrott
* [7e4740e] Refs #8941. Make sure we set the channum when switching to
  a new card with either a specific chanid or inputid.
* [05bc5e1] plugins configure: Remove some debugging left by mistake
* [ff593fa] Clean up the mappings for network control jump points.
* [146ee76] Fixes #8744. Fixes crash in DVB-x channel scanning.
* [6f24f3b] Subtitles: Rename the OSDSubFont setting to
  DefaultSubtitleFont.
* [6202c0d] Revert "Subtitles: Remove the OSDSubFont setting."
* [4a2420e] MythZoneMinder: Add support for the deep filesystem
  hierarchy for events.
* [a6b1e3a] Program editor: don't seek too far when stepping to the
  next keyframe.
* [97da8c8] Fix a doxygen comment
* [144c8bb] MythMusic: Do a full reload of the tracks and playlists
  after doing a scan
* [f78f999] Change delete behaviour so that we always use the deleted
  recording group allowing all recordings to be undeleted. By default
  we will only keep recordings for a minimum of 5 minutes (max ~20m)
  after their deletion, enough time to recover from a mistake but
  still free up space quickly. As before the user can specify to keep
  deleted recordings for a fixed number of days or until the space is
  needed for a new recording instead. Post 0.25 this change will allow
  us to strip out the old deletion code and simplify configuration
  process, the functional change is being made now to fix a couple of
  bugs caused by external processes such as MythPreviewGen blocking
  deletes from the UI. Fixes #9536
* [cfd3fc0] MythMusic: Fix the sending of the MUSIC_SETTINGS_CHANGED
  event
* [5932419] Merge branch 'compartist'
* [5206271] Subtitles: Apply OSDCC708TextZoom to CEA-608 captions as
  well.
* [99512fb] Refs #10386.  Don't sent EXIT_TO_MAIN event to Live TV
  jump point.
* [dfd909f] Fix crash on mac when no audio device exists.
* [bd68156] MythMusic: Fix the BLANKSCR keybinding not working
* [9016890] MythMusic: Check for some additional cdio headers
* [3570a99] MythMusic: Fix a memory leak in the playlist editor
* [7e6f5fa] Fixes #10386. Segfault fix. Check for null.
* [510da69] As noted in SHA1:9551bce2, MainServer doesn't know the
  actual recording status because it defaults to rsRecorded when the
  recordinginfo is initialized from the recorded table.  MainServer
  doesn't account for this and tries to make any needed state change
  which always ends up staying rsRecorded.  MainServer then passes
  this bad status to the scheduler.  If the recording had already
  failed, the rsFailed status gets overwritten.
* [3740d7d] Spelling consistency fixes
* [47d7c77] Fixes #9233. Refs #7408. Re-enables WindowResized().
* [a5447f1] MythMusic: Add a Compilations branch to the playlist
  editor
* [1824969] Fixes #10153. Guess at DVB-S vs DVB-S2 when not explicitly
  set.
* [21784ce] Fixes #10377. Prevent getting "stuck on a mux".
* [593d24b] Refs #10377. Some logging fixes. (VB_PLAYBACK-
  >VB_CHANNEL).
* [14ec737] Change the rsTuning UI state equivalent from 'tuning' to
  'running'. The UI states for the 'status' statetype are limited to 5
  generic values (normal, running, warning, error, disabled) to allow
  some portability to scenarios other than recording. (This was
  supposed to save themers some time and effort although it also binds
  their hands and doesn't allow as much creativity with how various
  recording states are represented. For this reason it may be re-
  visited post-0.25)
* [4d68d5e] Updated Russian MythFrontend, MythArchive, MythBrowser,
  MythGallery, MythGame, MythMusic, MythNews, MythWeather and
  MythZoneminder.
* [34c8767] Subtitles: fix an incorrect CEA-708 font mapping.
* [b967448] Fix the faulty exit code 139 issue in Ubuntu systems
* [723d798] Subtitles: improve vertical alignment for CEA-608
  captions.
* [1af1aec] Fixes display of position in the Program Lister.
  MythUIButtonList is zero indexed, to get a position for display we
  must add one.
* [967208b] Fix the last, hopefully, remaining places where
  livetvorder isn't honored.
* [0a301c0] Fix the scheduler to not write incorrect oldrecorded
  entries.
* [5d5aef3] Subtitles: improve the layout.
* [878d5eb] String consistency updated
* [456bb42] Updated Estonian MythFrontend and all plugins translation
  from Marko Punnar
* [e719d54] Replace tabs with spaces in Terra's schedule filter editor
  window xml
* [a3d9891] Use proper capitalization for some common words and
  prefixes.
* [5b19c4d] Populate the infomap from both RecordingRule and
  RecordingInfo if available. This fixes recording rule specific
  information not being available in the sub screens of the schedule
  editor.
* [f77d001] Fix minor problems editing in-progress recordings.
* [006ded1] Fix recording status strings being set to 'Not scheduled'
  when the reason for that is they were in the past and should have
  been marked as Recorded/Aborted/Failed/Cancelled/etc instead
* [6bedf81] Correct handling of unrelated argument after arg-less
  keyword.
* [7adbd54] Delay String processing until after QApplication has been
  initialized.
* [f613a43] Fix LiveTV switching by videosource to honor livetvorder.
* [9b5b7b5] Exit cutlist edit mode cleanly when executing a jump
  point.
* [c2a0b85] Updated British English translation MythFrontend
  translation from Nick Morrott.
* [307dac8] Make jump points work during playback when the OSD is
  present.
* [d59f4f4] Change dynamic cast to static. This is troubling because
  we rely on dynamic casts in so many places but for at least one
  person this cast was failing and causing popup menus in MythMusic to
  no longer have any effect. Maybe a buggy version of gcc?
* [3de87c3] Subtitles: Fix a logic error.
* [23d5167] Make host checks in Video Library scanner case
  insensitive.
* [5d7c01d] Cutlist editor: Update the edit bar for in-progress
  recordings.
* [1ce3d21] Cutlist editor: Adjust "Cut to End" behavior for an in-
  progress recording.
* [4a8546d] Merge branch 'master' of github.com:MythTV/mythtv
* [1d6485d] MythArchive consistency fixes.
* [89c34ef] Fix seeking backwards into a cut region.
* [6c3b564] Updated British English translation MythFrontend
  translation from Nick Morrott.
* [5501fff] Fix long-standing bug that always cleared
  record.next_record instead of updating it.
* [0c5de8e] Add missing menu closed event when closing the menu via
  the mouse. Fixes the menu dialog not working in some screens after
  being dismissed using a right click.
* [93c228d] Prevent crash when invoking the menu dialog via the right
  mouse button in Watch Recordings. ShowMenu() is a virtual method in
  MythScreenType, it's intended purpose is to load/display the context
  menu but here it is displaying a menu loaded elsewhere with no
  guards against duplicate popups being created. Move the menu display
  code to DisplayPopupMenu(), restore ShowMenu() to behave the same as
  the MENU key binding and re-instate the guards against multiple menu
  dialogs being created. Also fixes #10248 - 'Cannot delete recording
  if file is missing'
* [b755eca] Attempt to prevent a QString segfault if MythMenu changes
  while a dialog is open.
* [f3efafe] Fix segfault in MythUIButtonTree when list is empty and we
  attempt to navigate it. Refs #9101
* [b3e44a2] Rule type was missed from the RecordingRule text map.
  Added so that it appears twice in the map, once under the correct
  title of ruletype but also as rectype to be consistent with the
  ProgramInfo map until after 0.25 when we can rename that instance.
* [2075458] Remove deprecated attribute from dispatchNow(), we know
  it's deprecated but it's not going anywhere soon.
* [82fc1af] Add Collection support to developmental tmdb3 grabber.
* [0f0b0a7] Better backend metaclass, and people search support.
* [c47940a] Clean up and document background machinery
* [850fbc2] Replacement PagedList to temporarily work around bug in
  search API
* [d13addf] Add caching to tmdbv3 requests.
* [fe97f23] In progress TMDB v3 grabber script.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/env python
 
2
# -*- coding: utf-8 -*-
2
3
# mythburn.py
3
4
# The ported MythBurn scripts which feature:
4
5
 
30
31
# pyfribidi
31
32
 
32
33
# Optional (alternate demuxer)
33
 
# ProjectX - 0.90.4.00
34
 
 
35
 
#******************************************************************************
36
 
#******************************************************************************
37
 
#******************************************************************************
 
34
# ProjectX - >=0.91
 
35
 
 
36
#******************************************************************************
 
37
#******************************************************************************
 
38
#******************************************************************************
 
39
 
 
40
 
 
41
# All strings in this file should be unicode, not byte string!! They get converted to utf-8 only
 
42
 
 
43
 
 
44
 
38
45
 
39
46
# version of script - change after each update
40
 
VERSION="0.1.20111228-1"
 
47
VERSION="0.1.20120304-1"
41
48
 
42
49
# keep all temporary files for debugging purposes
43
50
# set this to True before a first run through when testing
256
263
 
257
264
def write(text, progress=True):
258
265
    """Simple place to channel all text output through"""
 
266
 
 
267
    text = text.encode("utf-8", "replace")
259
268
    sys.stdout.write(text + "\n")
260
269
    sys.stdout.flush()
261
270
 
270
279
    """Display an error message and exit app"""
271
280
    write("*"*60)
272
281
    write("ERROR: " + msg)
 
282
    write("See mythburn.log for more information.")
273
283
    write("*"*60)
274
284
    write("")
275
285
    saveSetting("MythArchiveLastRunResult", "Failed: " + quoteString(msg));
304
314
# Try to work out how many cpus we have available
305
315
 
306
316
def getCPUCount():
307
 
    """return the number of CPU's"""
 
317
    """return the number of CPUs"""
308
318
    cpustat = open("/proc/cpuinfo")
309
319
    cpudata = cpustat.readlines()
310
320
    cpustat.close()
338
348
    return os.path.exists( file )
339
349
 
340
350
#############################################################
341
 
# Escape quotes in a filename
 
351
# Escape quotes in a command line argument
342
352
 
343
 
def quoteFilename(filename):
344
 
    filename = filename.replace('"', '\\"')
345
 
    filename = filename.replace('`', '\\`')
346
 
    return '"%s"' % filename
 
353
def quoteCmdArg(arg):
 
354
    arg = arg.replace('"', '\\"')
 
355
    arg = arg.replace('`', '\\`')
 
356
    return '"%s"' % arg
347
357
 
348
358
#############################################################
349
359
# Returns the text contents from a given XML element.
406
416
        return videoresolution==(720,576) or videoresolution==(704,576) or videoresolution==(352,576) or videoresolution==(352,288)
407
417
 
408
418
#############################################################
409
 
# Romoves all the files from a directory
 
419
# Removes all the files from a directory
410
420
 
411
421
def deleteAllFilesInFolder(folder):
412
422
    """Does what it says on the tin!."""
415
425
                os.remove(os.path.join(root, name))
416
426
 
417
427
#############################################################
 
428
# Romoves all the objects from a directory
 
429
 
 
430
def deleteEverythingInFolder(folder):
 
431
    for root, dirs, files in os.walk(folder, topdown=False):
 
432
        for name in files:
 
433
                os.remove(os.path.join(root, name))
 
434
        for name in dirs:
 
435
                if os.path.islink(os.path.join(root, name)):
 
436
                    os.remove(os.path.join(root, name))
 
437
                else:
 
438
                    os.rmdir(os.path.join(root, name))
 
439
 
 
440
#############################################################
418
441
# Check to see if the user has cancelled the DVD creation process
419
442
 
420
443
def checkCancelFlag():
433
456
def runCommand(command):
434
457
    checkCancelFlag()
435
458
 
436
 
    result = os.system(command)
 
459
    # mytharchivehelper needes this locale to work correctly
 
460
    try:
 
461
       oldlocale = os.environ["LC_ALL"]
 
462
    except:
 
463
       oldlocale = ""
 
464
    os.putenv("LC_ALL", "en_US.UTF-8")
 
465
    result = os.system(command.encode('utf-8'))
 
466
    os.putenv("LC_ALL", oldlocale)
437
467
 
438
468
    if os.WIFEXITED(result):
439
469
        result = os.WEXITSTATUS(result)
464
494
 
465
495
    totalframes=int(musiclength * framespersecond)
466
496
 
467
 
    command = path_jpeg2yuv[0] + " -n %s -v0 -I p -f %s -j '%s' | %s -b 5000 -a %s -v 1 -f 8 -o '%s'" \
468
 
              % (totalframes, framespersecond, background, path_mpeg2enc[0], aspectratio, tempvideo)
 
497
    command = quoteCmdArg(path_jpeg2yuv[0]) + " -n %s -v0 -I p -f %s -j %s | %s -b 5000 -a %s -v 1 -f 8 -o %s" \
 
498
              % (totalframes, framespersecond, quoteCmdArg(background), quoteCmdArg(path_mpeg2enc[0]), aspectratio, quoteCmdArg(tempvideo))
469
499
    result = runCommand(command)
470
500
    if result<>0:
471
501
        fatalError("Failed while running jpeg2yuv - %s" % command)
472
502
 
473
 
    command = path_mplex[0] + " -f 8 -v 0 -o '%s' '%s' '%s'" % (tempmovie, tempvideo, music)
 
503
    command = quoteCmdArg(path_mplex[0]) + " -f 8 -v 0 -o %s %s %s" % (quoteCmdArg(tempmovie), quoteCmdArg(tempvideo), quoteCmdArg(music))
474
504
    result = runCommand(command)
475
505
    if result<>0:
476
506
        fatalError("Failed while running mplex - %s" % command)
477
507
 
478
508
    if xmlfile != "":
479
 
        command = path_spumux[0] + " -m dvd -s 0 '%s' < '%s' > '%s'" % (xmlfile, tempmovie, finaloutput)
 
509
        command = quoteCmdArg(path_spumux[0]) + " -m dvd -s 0 %s < %s > %s" % (quoteCmdArg(xmlfile), quoteCmdArg(tempmovie), quoteCmdArg(finaloutput))
480
510
        result = runCommand(command)
481
511
        if result<>0:
482
512
            fatalError("Failed while running spumux - %s" % command)
1431
1461
        data.thumblist = ','.join(thumblist)
1432
1462
 
1433
1463
    for k,v in data.items():
1434
 
        print "Node = %s, Data = %s" % (k, v)
 
1464
        write( "Node = %s, Data = %s" % (k, v))
1435
1465
        node = infoDOM.createElement(k)
1436
 
        node.appendChild(infoDOM.createTextNode(str(v)))
 
1466
        # v may be either an integer. Therefore we have to
 
1467
        # convert it to an unicode-string
 
1468
        # If it is already a string it is not encoded as all
 
1469
        # strings in this script are unicode. As no
 
1470
        # encoding-argument is supplied to unicode() it does
 
1471
        # nothing in this case.
 
1472
        node.appendChild(infoDOM.createTextNode(unicode(v)))
1437
1473
        top_element.appendChild(node)
1438
1474
 
1439
1475
    WriteXMLToFile (infoDOM, outputfile)
1497
1533
        if cpuCount > 1:
1498
1534
            cmd += "-threads %d " % cpuCount
1499
1535
 
1500
 
        cmd += "-i '%s' -f ac3 -ab 192k -ar 48000 '%s'" % (sourcefile, destinationfile)
 
1536
        cmd += "-i %s -f ac3 -ab 192k -ar 48000 %s" % (quoteCmdArg(sourcefile), quoteCmdArg(destinationfile))
1501
1537
        result = runCommand(cmd)
1502
1538
 
1503
1539
        if result != 0:
1591
1627
    # run spumux to add subtitles if they exist
1592
1628
    if os.path.exists(os.path.dirname(destination) + "/stream.d/spumux.xml"):
1593
1629
        write("Checking integrity of subtitle pngs")
1594
 
        command = os.path.join(scriptpath, "testsubtitlepngs.sh") + " %s/stream.d/spumux.xml" % (os.path.dirname(destination))
 
1630
        command = quoteCmdArg(os.path.join(scriptpath, "testsubtitlepngs.sh")) + " " + quoteCmdArg(os.path.dirname(destination) + "/stream.d/spumux.xml")
1595
1631
        result = runCommand(command)
1596
1632
        if result<>0:
1597
1633
            fatalError("Failed while running testsubtitlepngs.sh - %s" % command)
1598
1634
 
1599
1635
        write("Running spumux to add subtitles")
1600
 
        command = path_spumux[0] + " -P %s/stream.d/spumux.xml <%s >%s" % (os.path.dirname(destination), destination, os.path.splitext(destination)[0] + "-sub.mpg")
 
1636
        command = quoteCmdArg(path_spumux[0]) + " -P %s <%s >%s" % (quoteCmdArg(os.path.dirname(destination) + "/stream.d/spumux.xml"), quoteCmdArg(destination), quoteCmdArg(os.path.splitext(destination)[0] + "-sub.mpg"))
1601
1637
        result = runCommand(command)
1602
1638
        if result<>0:
1603
1639
            nonfatalError("Failed while running spumux.\n"
1615
1651
 
1616
1652
def getStreamInformation(filename, xmlFilename, lenMethod):
1617
1653
    """create a stream.xml file for filename"""
1618
 
    filename = quoteFilename(filename)
1619
 
    command = "mytharchivehelper -q -q --getfileinfo --infile %s --outfile %s --method %d" % (filename, xmlFilename, lenMethod)
 
1654
 
 
1655
    command = "mytharchivehelper -q -q --getfileinfo --infile %s --outfile %s --method %d" % (quoteCmdArg(filename), quoteCmdArg(xmlFilename), lenMethod)
 
1656
 
1620
1657
 
1621
1658
    result = runCommand(command)
1622
1659
 
1626
1663
 
1627
1664
    # print out the streaminfo.xml file to the log
1628
1665
    infoDOM = xml.dom.minidom.parse(xmlFilename)
1629
 
    write("streaminfo.xml :-\n" + infoDOM.toprettyxml("    ", ""), False)
 
1666
    write(xmlFilename + ":-\n" + infoDOM.toprettyxml("    ", ""), False)
1630
1667
 
1631
1668
#############################################################
1632
1669
# Gets the video width and height from a file's stream xml file
1672
1709
    if (localfile != ""):
1673
1710
        localfile = quoteFilename(localfile)
1674
1711
        if usecutlist == True:
1675
 
            command = "mythtranscode --mpeg2 --honorcutlist %s --infile %s --outfile %s" % (cutlist_s, localfile, destination)
 
1712
            command = "mythtranscode --mpeg2 --honorcutlist %s --infile %s --outfile %s" % (cutlist_s, quoteCmdArg(localfile), quoteCmdArg(destination))
1676
1713
        else:
1677
 
            command = "mythtranscode --mpeg2 -i %s -o %s" % (localfile, destination)
 
1714
            command = "mythtranscode --mpeg2 --infile %s --outfile %s" % (quoteCmdArg(localfile), quoteCmdArg(destination))
1678
1715
    else:
1679
1716
        if usecutlist == True:
1680
 
            command = "mythtranscode --mpeg2 --honorcutlist --chanid %s --starttime %s --outfile %s" % (chanid, starttime, destination)
 
1717
            command = "mythtranscode --mpeg2 --honorcutlist --chanid %s --starttime %s --outfile %s" % (chanid, starttime, quoteCmdArg(destination))
1681
1718
        else:
1682
 
            command = "mythtranscode --mpeg2 --chanid %s --starttime %s --outfile %s" % (chanid, starttime, destination)
 
1719
            command = "mythtranscode --mpeg2 --chanid %s --starttime %s --outfile %s" % (chanid, starttime, quoteCmdArg(destination))
1683
1720
 
1684
1721
    result = runCommand(command)
1685
1722
 
1736
1773
            write("Failed to generate Project-X cutlist.")
1737
1774
            return False
1738
1775
 
1739
 
    pxbasename = os.path.splitext(os.path.basename(file))[0]
1740
 
 
1741
1776
    if os.path.exists(file) != True:
1742
1777
        write("Error: input file doesn't exist on local filesystem")
1743
1778
        return False
1744
1779
 
1745
 
 
1746
 
    qdestdir = quoteFilename(folder)
1747
 
    qpxbasename = quoteFilename(pxbasename)
1748
 
    qfile = quoteFilename(file)
1749
 
    qcutlist = os.path.join(folder, "cutlist_x.txt")
1750
 
 
1751
 
    command = path_projectx[0] + " -id %s" % getStreamList(folder)
 
1780
    command = quoteCmdArg(path_projectx[0]) + " %s -id '%s' -set ExternPanel.appendPidToFileName=1 -out %s -name stream" % (quoteCmdArg(file), getStreamList(folder), quoteCmdArg(folder))
1752
1781
    if usecutlist == True:
1753
 
        command += " -cut %s -out %s -name %s %s" % (qcutlist, qdestdir, qpxbasename, qfile)
1754
 
    else:
1755
 
        command += " -out %s -name %s %s" % (qdestdir, qpxbasename, qfile)
1756
 
 
 
1782
        command += " -cut %s" % quoteCmdArg(os.path.join(folder, "cutlist_x.txt"))
1757
1783
    write(command)
1758
 
 
1759
1784
    result = runCommand(command)
1760
1785
 
1761
1786
    if (result != 0):
1765
1790
 
1766
1791
 
1767
1792
    # workout which files we need and rename them
1768
 
    renameProjectXFiles(folder, pxbasename)
 
1793
    video, audio1, audio2 = selectStreams(folder)
 
1794
    if addSubtitles:
 
1795
        subtitles = selectSubtitleStream(folder)
 
1796
 
 
1797
    videoID_hex = "0x%x" % video[VIDEO_ID]
 
1798
    if audio1[AUDIO_ID] != -1:
 
1799
        audio1ID_hex = "0x%x" % audio1[AUDIO_ID]
 
1800
    else:
 
1801
        audio1ID_hex = ""
 
1802
    if audio2[AUDIO_ID] != -1:
 
1803
        audio2ID_hex = "0x%x" % audio2[AUDIO_ID]
 
1804
    else:
 
1805
        audio2ID_hex = ""
 
1806
    if addSubtitles and subtitles[SUBTITLE_ID] != -1:
 
1807
        subtitlesID_hex = "0x%x" % subtitles[SUBTITLE_ID]
 
1808
    else:
 
1809
        subtitlesID_hex = ""
 
1810
 
 
1811
 
 
1812
    files = os.listdir(folder)
 
1813
    for file in files:
 
1814
        if file[0:9] == "stream{0x": # don't rename files that have already been renamed
 
1815
            PID = file[7:13]
 
1816
            SubID = file[19:23]
 
1817
            if PID == videoID_hex or SubID == videoID_hex:
 
1818
                os.rename(os.path.join(folder, file), os.path.join(folder, "stream.mv2"))
 
1819
            elif PID == audio1ID_hex or SubID == audio1ID_hex:
 
1820
                os.rename(os.path.join(folder, file), os.path.join(folder, "stream0." + file[-3:]))
 
1821
            elif PID == audio2ID_hex or SubID == audio2ID_hex:
 
1822
                os.rename(os.path.join(folder, file), os.path.join(folder, "stream1." + file[-3:]))
 
1823
            elif PID == subtitlesID_hex or SubID == subtitlesID_hex:
 
1824
                if file[-3:] == "sup":
 
1825
                    os.rename(os.path.join(folder, file), os.path.join(folder, "stream.sup"))
 
1826
                else:
 
1827
                    os.rename(os.path.join(folder, file), os.path.join(folder, "stream.sup.IFO"))
 
1828
 
 
1829
 
 
1830
    # Fallback if assignment and renaming by ID failed
 
1831
 
 
1832
    files = os.listdir(folder)
 
1833
    for file in files:
 
1834
        if file[0:9] == "stream{0x": # don't rename files that have already been renamed
 
1835
            if not os.path.exists(os.path.join(folder, "stream.mv2")) and file[-3:] == "m2v":
 
1836
                os.rename(os.path.join(folder, file), os.path.join(folder, "stream.mv2"))
 
1837
            elif not (os.path.exists(os.path.join(folder, "stream0.ac3")) or os.path.exists(os.path.join(folder, "stream0.mp2"))) and file[-3:] == "ac3":
 
1838
                os.rename(os.path.join(folder, file), os.path.join(folder, "stream0.ac3"))
 
1839
            elif not (os.path.exists(os.path.join(folder, "stream0.ac3")) or os.path.exists(os.path.join(folder, "stream0.mp2"))) and file[-3:] == "mp2":
 
1840
                os.rename(os.path.join(folder, file), os.path.join(folder, "stream0.mp2"))
 
1841
            elif not (os.path.exists(os.path.join(folder, "stream1.ac3")) or os.path.exists(os.path.join(folder, "stream1.mp2"))) and file[-3:] == "ac3":
 
1842
                os.rename(os.path.join(folder, file), os.path.join(folder, "stream1.ac3"))
 
1843
            elif not (os.path.exists(os.path.join(folder, "stream1.ac3")) or os.path.exists(os.path.join(folder, "stream1.mp2"))) and file[-3:] == "mp2":
 
1844
                os.rename(os.path.join(folder, file), os.path.join(folder, "stream1.mp2"))
 
1845
            elif not os.path.exists(os.path.join(folder, "stream.sup")) and file[-3:] == "sup":
 
1846
                os.rename(os.path.join(folder, file), os.path.join(folder, "stream.sup"))
 
1847
            elif not os.path.exists(os.path.join(folder, "stream.sup.IFO")) and file[-3:] == "IFO":
 
1848
                os.rename(os.path.join(folder, file), os.path.join(folder, "stream.sup.IFO"))
 
1849
 
1769
1850
 
1770
1851
    # if we have some dvb subtitles and the user wants to add them to the DVD
1771
1852
    # convert them to pngs and create the spumux xml file
1774
1855
            os.path.exists(os.path.join(folder, "stream.sup.IFO"))):
1775
1856
            write("Found DVB subtitles converting to DVD subtitles")
1776
1857
            command = "mytharchivehelper -q -q --sup2dast "
1777
 
            command += " --infile %s --ifofile %s --delay 0" % (os.path.join(folder, "stream.sup"), os.path.join(folder, "stream.sup.IFO"))
 
1858
            command += " --infile %s --ifofile %s --delay 0" % (quoteCmdArg(os.path.join(folder, "stream.sup")), quoteCmdArg(os.path.join(folder, "stream.sup.IFO")))
1778
1859
 
1779
1860
            result = runCommand(command)
1780
1861
 
1789
1870
    return True
1790
1871
 
1791
1872
#############################################################
1792
 
# find the required stream files and rename them
1793
 
 
1794
 
def renameProjectXFiles(folder, pxbasename):
1795
 
 
1796
 
    write("renameProjectXFiles start -----------------------------------------", False)
1797
 
    logf = open(os.path.join(folder, pxbasename + "_log.txt"))
1798
 
    logdata = logf.readlines()
1799
 
    logf.close()
1800
 
 
1801
 
    # find stream PIDs and Files
1802
 
    streamIds = []
1803
 
    streamFiles = []    
1804
 
    for line in logdata:
1805
 
         tokens = line.split()
1806
 
         if len(tokens) > 0:
1807
 
            if tokens[0] == "++>":
1808
 
              # From ProjectX/resources/pjxresources_en.properties:
1809
 
              if tokens[1] == "Mpg":
1810
 
                if tokens[2] == "Video:":
1811
 
                  write("found MPEG video stream %s" % tokens[4], False)
1812
 
                  streamIds.append(int(tokens[4], 16))
1813
 
                if tokens[2] == "Audio:":
1814
 
                  write("found MPEG audio stream %s" % tokens[4], False)
1815
 
                  streamIds.append(int(tokens[4], 16))
1816
 
              if tokens[1] == "AC3/DTS":
1817
 
                write("found AC3/DTS audio stream %s" % tokens[4], False)
1818
 
                streamIds.append(int(tokens[4], 16))              
1819
 
              if tokens[1] == "LPCM":
1820
 
                write("found LPCM audio stream %s" % tokens[4], False)
1821
 
                streamIds.append(int(tokens[4], 16))             
1822
 
              if tokens[1] == "Teletext:":
1823
 
                write("found Teletext stream %s" % tokens[3], False)
1824
 
                streamIds.append(int(tokens[3], 16))              
1825
 
              if tokens[1] == "Subpicture:":
1826
 
                write("found Subpicture stream %s" % tokens[3], False)
1827
 
                streamIds.append(int(tokens[3], 16))
1828
 
              if tokens[1] == "Generic_VBI:":
1829
 
                write("found Generic_VBI stream %s" % tokens[3], False)
1830
 
                streamIds.append(int(tokens[3], 16))                                            
1831
 
            if tokens[0] == "--->":
1832
 
              if tokens[1] == "new":
1833
 
                if tokens[2] == "File:":
1834
 
                  write("found file for stream 0x%x, %s" % (streamIds[len(streamIds)-1], tokens[3]), False)
1835
 
                  streamFiles.append(tokens[3].replace("'","")) # let's hope the path never has a space in it
1836
 
            if tokens[0] == "-->":
1837
 
              if tokens[1] == "stream":
1838
 
                if tokens[2] == "omitted":
1839
 
                  write("stream 0x%x omitted" % streamIds[len(streamIds)-1], False)
1840
 
                  streamFiles.append("")
1841
 
                  
1842
 
    write("streadmIds=%s" % streamIds)
1843
 
    write("streamFiles=%s" % streamFiles)
1844
 
 
1845
 
    # choose which streams we need
1846
 
    video, audio1, audio2 = selectStreams(folder)
1847
 
 
1848
 
    if getFileType(folder) == "mpeg":
1849
 
        videoID  = video[VIDEO_ID] & 255
1850
 
        audio1ID = audio1[AUDIO_ID] & 255
1851
 
        audio2ID = audio2[AUDIO_ID] & 255
1852
 
    else:
1853
 
        videoID  = video[VIDEO_ID]
1854
 
        audio1ID = audio1[AUDIO_ID]
1855
 
        audio2ID = audio2[AUDIO_ID]
1856
 
 
1857
 
    # sanity check - we should have a file for each ID
1858
 
    if len(streamIds) == len(streamFiles):
1859
 
        # loop thought the available streams looking for the ones we want
1860
 
        for stream in streamIds:
1861
 
            write("got stream: %d" % stream, False)
1862
 
            if stream == videoID:
1863
 
                write("found video streamID", False)
1864
 
                if os.path.exists(streamFiles[streamIds.index(stream)]):
1865
 
                    write("found video stream file", False)
1866
 
                    os.rename(streamFiles[streamIds.index(stream)], os.path.join(folder, "stream.mv2"))
1867
 
 
1868
 
            if stream == audio1ID:
1869
 
                write("found audio1 streamID", False)
1870
 
                if os.path.exists(streamFiles[streamIds.index(stream)]):
1871
 
                    write("found audio1 stream file", False)
1872
 
                    if audio1[AUDIO_CODEC] == "AC3":
1873
 
                        os.rename(streamFiles[streamIds.index(stream)], os.path.join(folder, "stream0.ac3"))
1874
 
                    else:
1875
 
                        os.rename(streamFiles[streamIds.index(stream)], os.path.join(folder, "stream0.mp2"))
1876
 
 
1877
 
            if stream == audio2ID:
1878
 
                write("found audio2 streamID", False)
1879
 
                if os.path.exists(streamFiles[streamIds.index(stream)]):
1880
 
                    write("found audio2 stream file", False)
1881
 
                    if audio2[AUDIO_CODEC] == "AC3":
1882
 
                        os.rename(streamFiles[streamIds.index(stream)], os.path.join(folder, "stream1.ac3"))
1883
 
                    else:
1884
 
                        os.rename(streamFiles[streamIds.index(stream)], os.path.join(folder, "stream1.mp2"))
1885
 
 
1886
 
    # final chance to find the correct stream files
1887
 
    if not os.path.exists(os.path.join(folder, "stream.mv2")):
1888
 
        if os.path.exists(os.path.join(folder, pxbasename + ".m2v")):
1889
 
            os.rename(os.path.join(folder, pxbasename + ".m2v"), os.path.join(folder, "stream.mv2"))
1890
 
 
1891
 
    if not os.path.exists(os.path.join(folder, "stream0.mp2")) or not os.path.exists(os.path.join(folder, "stream0.ac3")):
1892
 
        if os.path.exists(os.path.join(folder, pxbasename + ".mp2")):
1893
 
            os.rename(os.path.join(folder, pxbasename + ".mp2"), os.path.join(folder, "stream0.mp2"))
1894
 
        if os.path.exists(os.path.join(folder, pxbasename + ".ac3")):
1895
 
            os.rename(os.path.join(folder, pxbasename + ".ac3"), os.path.join(folder, "stream0.ac3"))
1896
 
 
1897
 
    if not os.path.exists(os.path.join(folder, "stream1.mp2")) or not os.path.exists(os.path.join(folder, "stream1.ac3")):
1898
 
        if os.path.exists(os.path.join(folder, pxbasename + "[1].mp2")):
1899
 
            os.rename(os.path.join(folder, pxbasename + "[1].mp2"), os.path.join(folder, "stream1.mp2"))
1900
 
        if os.path.exists(os.path.join(folder, pxbasename + "[1].ac3")):
1901
 
            os.rename(os.path.join(folder, pxbasename + "[1].ac3"), os.path.join(folder, "stream1.ac3"))
1902
 
 
1903
 
    # do we have any subtitle files
1904
 
    if os.path.exists(os.path.join(folder, pxbasename + ".sup")):
1905
 
        os.rename(os.path.join(folder, pxbasename + ".sup"), os.path.join(folder, "stream.sup"))
1906
 
 
1907
 
    if os.path.exists(os.path.join(folder, pxbasename + ".sup.IFO")):
1908
 
        os.rename(os.path.join(folder, pxbasename + ".sup.IFO"), os.path.join(folder, "stream.sup.IFO"))
1909
 
 
1910
 
    write("renameProjectXFiles end -----------------------------------------", False)
1911
 
 
1912
 
#############################################################
1913
1873
# convert time stamp to pts
1914
1874
 
1915
1875
def ts2pts(time):
1980
1940
        else:
1981
1941
            fr=framerateNTSC
1982
1942
 
1983
 
        source = quoteFilename(source)
1984
 
 
1985
 
        command = "mytharchivehelper -q -q --createthumbnail --infile %s --thumblist '%s' --outfile %s" % (source, seconds, destination)
 
1943
        command = "mytharchivehelper -q -q --createthumbnail --infile %s --thumblist '%s' --outfile %s" % (quoteCmdArg(source), seconds, quoteCmdArg(destination))
1986
1944
        result = runCommand(command)
1987
1945
        if result <> 0:
1988
1946
            fatalError("Failed while running mytharchivehelper to get thumbnails.\n"
2005
1963
    write("Extracting thumbnail images from: %s - at %s" % (source, thumbList))
2006
1964
    write("Destination file %s" % destination)
2007
1965
 
2008
 
    source = quoteFilename(source)
2009
 
 
2010
 
    command = "mytharchivehelper -q -q --createthumbnail --infile %s --thumblist '%s' --outfile %s" % (source, thumbList, destination)
 
1966
    command = "mytharchivehelper -q -q --createthumbnail --infile %s --thumblist '%s' --outfile %s" % (quoteCmdArg(source), thumbList, quoteCmdArg(destination))
 
1967
    write(command)
2011
1968
    result = runCommand(command)
2012
1969
    if result <> 0:
2013
1970
        fatalError("Failed while running mytharchivehelper to get thumbnails.\n"
2036
1993
 
2037
1994
        # do some parameter substitution
2038
1995
        if value == "%inputfile":
2039
 
            value = quoteFilename(source)
 
1996
            value = quoteCmdArg(source)
2040
1997
        if value == "%outputfile":
2041
 
            value = quoteFilename(destvideofile)
 
1998
            value = quoteCmdArg(destvideofile)
2042
1999
        if value == "%aspect":
2043
2000
            value = aspectratio
2044
2001
 
2092
2049
        passLog = os.path.join(getTempPath(), 'pass')
2093
2050
 
2094
2051
        pass1 = string.replace(command, "%passno","1")
2095
 
        pass1 = string.replace(pass1, "%passlogfile", passLog)
 
2052
        pass1 = string.replace(pass1, "%passlogfile", quoteCmdArg(passLog))
2096
2053
        write("Pass 1 - " + pass1)
2097
2054
        result = runCommand(pass1)
2098
2055
 
2214
2171
    if cpuCount > 1:
2215
2172
        command += "-threads %d " % cpuCount
2216
2173
 
2217
 
    command += "-f s16le -ar %s -ac %s -i %s " % (samplerate, channels, os.path.join(folder, "audout")) 
 
2174
    command += "-f s16le -ar %s -ac %s -i %s " % (samplerate, channels, quoteCmdArg(os.path.join(folder, "audout"))) 
2218
2175
    command += "-f rawvideo -pix_fmt yuv420p -s %s -aspect %s -r %s " % (videores, aspectratio, fps)
2219
 
    command += "-i %s " % os.path.join(folder, "vidout")
 
2176
    command += "-i %s " % quoteCmdArg(os.path.join(folder, "vidout"))
2220
2177
    command += "-aspect %s -r %s " % (aspectratio, fps)
2221
2178
    if (deinterlace == 1):
2222
2179
        command += "-deinterlace "
2224
2181
    command += "-s %s -b %s -vcodec mpeg2video " % (outvideores, outvideobitrate)
2225
2182
    command += "-qmin %s -qmax %s -qdiff %s " % (qmin, qmax, qdiff)
2226
2183
    command += "-ab %s -ar %s -acodec %s " % (outaudiobitrate, outaudiosamplerate, outaudiocodec)
2227
 
    command += "-f dvd %s" % quoteFilename(destvideofile)
 
2184
    command += "-f dvd %s" % quoteCmdArg(destvideofile)
2228
2185
 
2229
2186
    #wait for mythtranscode to create the fifos
2230
2187
    tries = 30
2261
2218
def CreateDVDISO(title):
2262
2219
    write("Creating ISO image")
2263
2220
    checkCancelFlag()
2264
 
    command = path_mkisofs[0] + ' -dvd-video '
2265
 
    command += ' -V ' + quoteFilename(title)
2266
 
    command += ' -o ' + os.path.join(getTempPath(), 'mythburn.iso')
2267
 
    command += " " + os.path.join(getTempPath(),'dvd')
 
2221
    command = quoteCmdArg(path_mkisofs[0]) + ' -dvd-video '
 
2222
    command += ' -V ' + quoteCmdArg(title)
 
2223
    command += ' -o ' + quoteCmdArg(os.path.join(getTempPath(), 'mythburn.iso'))
 
2224
    command += " " + quoteCmdArg(os.path.join(getTempPath(),'dvd'))
2268
2225
 
2269
2226
    result = runCommand(command)
2270
2227
 
2279
2236
 
2280
2237
def BurnDVDISO(title):
2281
2238
    write( "Burning ISO image to %s" % dvddrivepath)
2282
 
    checkCancelFlag()
2283
2239
 
2284
 
    finished = False
2285
 
    tries = 0
2286
 
    while not finished and tries < 10:
 
2240
    #######################
 
2241
    # some helper functions
 
2242
    def drivestatus():
2287
2243
        f = os.open(dvddrivepath, os.O_RDONLY | os.O_NONBLOCK)
2288
 
        drivestatus = ioctl(f,CDROM.CDROM_DRIVE_STATUS, 0)
2289
 
        os.close(f);
2290
 
 
2291
 
        if drivestatus == CDROM.CDS_DISC_OK or drivestatus == CDROM.CDS_NO_INFO:
 
2244
        status = ioctl(f,CDROM.CDROM_DRIVE_STATUS, 0)
 
2245
        os.close(f)
 
2246
        return status
 
2247
    def displayneededdisktype():
 
2248
        if mediatype == DVD_SL:
 
2249
          write("Please insert an empty single-layer disc (DVD+R or DVD-R).")
 
2250
        if mediatype == DVD_DL:
 
2251
          write("Please insert an empty double-layer disc (DVD+R DL or DVD-R DL).")
 
2252
        if mediatype == DVD_RW:
 
2253
          write("Please insert a rewritable disc (DVD+RW or DVD-RW).")
 
2254
    def tray(action):
 
2255
        runCommand("pumount " + quoteCmdArg(dvddrivepath));
 
2256
        waitForDrive()
 
2257
        try:
 
2258
            f = os.open(drivepath, os.O_RDONLY | os.O_NONBLOCK)
 
2259
            r = ioctl(f,action, 0)
 
2260
            os.close(f)
 
2261
            return True
 
2262
        except:
 
2263
            write("Failed to eject the disc!")
 
2264
            return False
 
2265
        finally:
 
2266
            os.close(f)
 
2267
    def waitForDrive():
 
2268
        tries = 0
 
2269
        while drivestatus() == CDROM.CDS_DRIVE_NOT_READY:
 
2270
            checkCancelFlag()
 
2271
            write("Waiting for drive")
 
2272
            time.sleep(5)
 
2273
            tries += 1
 
2274
            if tries > 10:
 
2275
                # Try a hard reset if the device is still not ready
 
2276
                write("Try a hard-reset of the device")
 
2277
                tray(CDROM.CDROMRESET)
 
2278
                tries = 0
 
2279
 
 
2280
 
 
2281
    ####################
 
2282
    # start working here
 
2283
 
 
2284
 
 
2285
    finished = False
 
2286
    while not finished:
 
2287
        # Maybe the user has no appropriate medium or something alike. Give her the chance to cancel.
 
2288
        checkCancelFlag()
 
2289
 
 
2290
        # If drive needs some time (for example to close the tray) give it to it
 
2291
        waitForDrive()
 
2292
 
 
2293
        if drivestatus() == CDROM.CDS_DISC_OK or drivestatus() == CDROM.CDS_NO_INFO:
2292
2294
 
2293
2295
            # If the frontend has a previously burnt DVD+RW mounted,
2294
2296
            # growisofs will fail to burn it, so try to pumount it first...
2295
 
            runCommand("pumount " + dvddrivepath);
2296
 
 
 
2297
            runCommand("pumount " + quoteCmdArg(dvddrivepath));
 
2298
 
 
2299
 
 
2300
            command = quoteCmdArg(path_growisofs[0]) + " -dvd-compat"
 
2301
            if drivespeed != 0:
 
2302
                command += " -speed=%d" % drivespeed
2297
2303
            if mediatype == DVD_RW and erasedvdrw == True:
2298
 
                command = path_growisofs[0] + " -dvd-compat "
2299
 
                if drivespeed != 0:
2300
 
                    command += "-speed=%d " % drivespeed
2301
 
                command += " -use-the-force-luke -Z " + dvddrivepath 
2302
 
                command += " -dvd-video -V '" + title.replace("'", "'\\''") + "' "
2303
 
                command += os.path.join(getTempPath(),'dvd')
2304
 
            else:
2305
 
                command = path_growisofs[0] + " -dvd-compat "
2306
 
                if drivespeed != 0:
2307
 
                    command += "-speed=%d " % drivespeed
2308
 
                command += " -Z " + dvddrivepath + " -dvd-video -V '" + title.replace("'", "'\\''") + "' "
2309
 
                command += os.path.join(getTempPath(),'dvd')
2310
 
 
 
2304
                command += " -use-the-force-luke"
 
2305
            command += " -Z " + quoteCmdArg(dvddrivepath) + " -dvd-video -V " + quoteCmdArg(title) + " " + quoteCmdArg(os.path.join(getTempPath(),'dvd'))
2311
2306
            write(command)
2312
2307
            write("Running growisofs to burn DVD")
2313
2308
 
2314
2309
            result = runCommand(command)
2315
 
            if result != 0:
2316
 
                write("-"*60)
2317
 
                write("ERROR: Failed while running growisofs.")
2318
 
                write("Result %d, Command was: %s" % (result, command))
2319
 
                write("Please check the troubleshooting section of the README for ways to fix this error")
2320
 
                write("-"*60)
2321
 
                write("")
2322
 
                sys.exit(1)
2323
 
            finished = True
2324
 
 
2325
 
            try:
2326
 
                # eject the burned disc
2327
 
                f = os.open(dvddrivepath, os.O_RDONLY | os.O_NONBLOCK)
2328
 
                r = ioctl(f,CDROM.CDROMEJECT, 0)
2329
 
                os.close(f)
2330
 
            except:
2331
 
                write("Failed to eject the disc! "
2332
 
                      "Maybe the media monitor has mounted it")
2333
 
 
2334
 
        elif drivestatus == CDROM.CDS_TRAY_OPEN:
2335
 
            # Give the user 10secs to close the Tray
 
2310
            if result == 0:
 
2311
                finished = True
 
2312
            else:
 
2313
                if result == 252:
 
2314
                    write("-"*60)
 
2315
                    write("You probably inserted a medium of wrong type.")
 
2316
                elif (result == 156):
 
2317
                    write("-"*60)
 
2318
                    write("You probably inserted a non-empty, corrupt or too small medium.")
 
2319
                elif (result == 144):
 
2320
                    write("-"*60)
 
2321
                    write("You inserted a non-empty medium.")
 
2322
                else:
 
2323
                    write("-"*60)
 
2324
                    write("ERROR: Failed while running growisofs.")
 
2325
                    write("Result %d, Command was: %s" % (result, command))
 
2326
                    write("Please check mythburn.log for further information")
 
2327
                    write("-"*60)
 
2328
                    write("")
 
2329
                    write("Going to try it again until canceled by user:")
 
2330
                    write("-"*60)
 
2331
                    write("")
 
2332
                displayneededdisktype()
 
2333
 
 
2334
            # eject the disc
 
2335
            tray(CDROM.CDROMEJECT)
 
2336
 
 
2337
 
 
2338
        elif drivestatus() == CDROM.CDS_TRAY_OPEN:
 
2339
            displayneededdisktype()
2336
2340
            write("Waiting for tray to close.")
2337
 
            time.sleep(10)
2338
 
        elif drivestatus == CDROM.CDS_NO_DISC:
2339
 
            # Open the Tray, if there is one.
2340
 
            write("Opening tray to get it fed with a DVD.")
2341
 
            f = os.open(dvddrivepath, os.O_RDONLY | os.O_NONBLOCK)
2342
 
            ioctl(f,CDROM.CDROMEJECT, 0)
2343
 
            os.close(f);
2344
 
        elif drivestatus == CDROM.CDS_DRIVE_NOT_READY:
2345
 
            # Try a hard reset
2346
 
            write("Trying a hard-reset of the device")
2347
 
            f = os.open(dvddrivepath, os.O_RDONLY | os.O_NONBLOCK)
2348
 
            ioctl(f,CDROM.CDROMEJECT, 0)
2349
 
            os.close(f);
2350
 
 
2351
 
        time.sleep(1)
2352
 
        tries += 1
2353
 
 
2354
 
    if not finished:
2355
 
        fatalError("Tried 10 times to get a good status from DVD drive - Giving up!")
 
2341
            # Wait until user closes tray or cancels
 
2342
            while drivestatus() == CDROM.CDS_TRAY_OPEN:
 
2343
                checkCancelFlag()
 
2344
                time.sleep(5)
 
2345
        elif drivestatus() == CDROM.CDS_NO_DISC:
 
2346
            tray(CDROM.CDROMEJECT)
 
2347
            displayneededdisktype()
2356
2348
 
2357
2349
    write("Finished burning ISO image")
2358
2350
 
2363
2355
def deMultiplexMPEG2File(folder, mediafile, video, audio1, audio2):
2364
2356
 
2365
2357
    if getFileType(folder) == "mpegts":
2366
 
        command = "mythreplex --demux --fix_sync -t TS -o %s " % (folder + "/stream")
 
2358
        command = "mythreplex --demux --fix_sync -t TS -o %s " % quoteCmdArg(folder + "/stream")
2367
2359
        command += "-v %d " % (video[VIDEO_ID])
2368
2360
 
2369
2361
        if audio1[AUDIO_ID] != -1: 
2383
2375
                command += "-c %d " % (audio2[AUDIO_ID])
2384
2376
 
2385
2377
    else:
2386
 
        command = "mythreplex --demux --fix_sync -o %s " % (folder + "/stream")
 
2378
        command = "mythreplex --demux --fix_sync -o %s " % quoteCmdArg(folder + "/stream")
2387
2379
        command += "-v %d " % (video[VIDEO_ID] & 255)
2388
2380
 
2389
2381
        if audio1[AUDIO_ID] != -1: 
2403
2395
            elif audio2[AUDIO_CODEC] == 'EAC3':
2404
2396
                command += "-c %d " % (audio2[AUDIO_ID] & 255)
2405
2397
 
2406
 
    mediafile = quoteFilename(mediafile)
 
2398
    mediafile = quoteCmdArg(mediafile)
2407
2399
    command += mediafile
2408
2400
    write("Running: " + command)
2409
2401
 
2420
2412
    M2Vsize0 = os.path.getsize(source)
2421
2413
    write("Initial M2Vsize is %.2f Mb , target is %.2f Mb" % ( (float(M2Vsize0)/mega), (float(M2Vsize0)/(factor*mega)) ))
2422
2414
 
2423
 
    command = path_M2VRequantiser[0]   
 
2415
    command = quoteCmdArg(path_M2VRequantiser[0])
2424
2416
    command += " %.5f "  % factor
2425
2417
    command += " %s "  % M2Vsize0
2426
 
    command += " <  %s " % source
2427
 
    command += " >  %s " % destination
 
2418
    command += " <  %s " % quoteCmdArg(source)
 
2419
    command += " >  %s " % quoteCmdArg(destination)
2428
2420
 
2429
2421
    write("Running: " + command)
2430
2422
    result = runCommand(command)
 
2423
    if result<>0:
 
2424
        fatalError("Failed while running M2VRequantiser. Command was %s" % command)
2431
2425
 
2432
2426
    M2Vsize1 = os.path.getsize(destination)
2433
2427
       
2434
2428
    write("M2Vsize after requant is  %.2f Mb " % (float(M2Vsize1)/mega))
2435
2429
    fac1=float(M2Vsize0) / float(M2Vsize1)
2436
2430
    write("Factor demanded %.5f, achieved %.5f, ratio %.5f " % ( factor, fac1, fac1/factor))
2437
 
            
2438
 
    if result<>0:
2439
 
        fatalError("Failed while running M2VRequantiser. Command was %s" % command)
2440
2431
 
2441
2432
#############################################################
2442
2433
# Calculates the total size of all the video, audio and menu files 
3195
3186
                height = getScaledAttribute(node, "h")
3196
3187
                frames = int(secondsToFrames(menulength))
3197
3188
 
3198
 
                command = "mytharchivehelper -q -q --createthumbnail --infile  %s --thumblist '%s' --outfile '%s' --framecount %d" % (inputfile, starttime, outputfile, frames)
 
3189
                command = "mytharchivehelper -q -q --createthumbnail --infile  %s --thumblist '%s' --outfile %s --framecount %d" % (quoteCmdArg(inputfile), starttime, quoteCmdArg(outputfile), frames)
3199
3190
                result = runCommand(command)
3200
3191
                if (result != 0):
3201
3192
                    write( "mytharchivehelper failed with code %d. Command = %s" % (result, command) )
4061
4052
    # 2. if there is one or more stream(s) using the 2nd preferred language we use that
4062
4053
    # 3. if we still haven't found a stream we use the stream with the lowest PID
4063
4054
    # 4. we prefer ac3 over mp2
4064
 
    # 5. if there are more that one stream with the chosen language we use the one with the lowest PID
 
4055
    # 5. if there are more than one stream with the chosen language we use the one with the lowest PID
4065
4056
 
4066
4057
    write("Preferred audio languages %s and %s" % (preferredlang1, preferredlang2))
4067
4058
 
4785
4776
        tmpfile = node.attributes["filename"].value
4786
4777
        filename = os.path.basename(tmpfile)
4787
4778
 
4788
 
        res = runCommand("mytharchivehelper -q -q --isremote --infile " + quoteFilename(tmpfile))
 
4779
        res = runCommand("mytharchivehelper -q -q --isremote --infile " + quoteCmdArg(tmpfile))
4789
4780
        if res == 2:
4790
4781
            # file is on a remote filesystem so copy it to a local file
4791
4782
            write("Copying file from " + tmpfile)
4850
4841
 
4851
4842
        write( "Final DVD Video format will be " + videomode)
4852
4843
 
4853
 
        #Ensure the destination dvd folder is empty
4854
 
        if doesFileExist(os.path.join(getTempPath(),"dvd")):
4855
 
            deleteAllFilesInFolder(os.path.join(getTempPath(),"dvd"))
4856
4844
 
4857
4845
        #Loop through all the files
4858
4846
        files=media[0].getElementsByTagName("file")
4862
4850
 
4863
4851
            if debug_secondrunthrough==False:
4864
4852
                #Delete all the temporary files that currently exist
4865
 
                deleteAllFilesInFolder(getTempPath())
 
4853
                deleteEverythingInFolder(getTempPath())
4866
4854
 
4867
4855
            #If User wants to, copy remote files to a tmp dir
4868
4856
            if copyremoteFiles==True:
4869
4857
                if debug_secondrunthrough==False:
4870
4858
                    localCopyFolder=os.path.join(getTempPath(),"localcopy")
4871
 
                    #If it already exists destroy it to remove previous debris
4872
 
                    if os.path.exists(localCopyFolder):
4873
 
                        #Remove all the files first
4874
 
                        deleteAllFilesInFolder(localCopyFolder)
4875
 
                        #Remove the folder
4876
 
                        os.rmdir (localCopyFolder)
4877
4859
                    os.makedirs(localCopyFolder)
4878
4860
                files=copyRemote(files,getTempPath())
4879
4861
 
4887
4869
                folder=getItemTempPath(filecount)
4888
4870
 
4889
4871
                if debug_secondrunthrough==False:
4890
 
                    #If it already exists destroy it to remove previous debris
4891
 
                    if os.path.exists(folder):
4892
 
                        #Remove all the files first
4893
 
                        deleteAllFilesInFolder(folder)
4894
 
                        subtitlefolder = os.path.join(folder, "stream.d")
4895
 
                        if os.path.exists(subtitlefolder):
4896
 
                            deleteAllFilesInFolder(subtitlefolder)
4897
 
                            os.rmdir(subtitlefolder)
4898
 
                        previewfolder = os.path.join(folder, "preview")
4899
 
                        if os.path.exists(previewfolder):
4900
 
                            deleteAllFilesInFolder(previewfolder)
4901
 
                            os.rmdir(previewfolder)
4902
 
                        #Remove the folder
4903
 
                        os.rmdir (folder)
4904
4872
                    os.makedirs(folder)
4905
4873
                #Do the pre-process work
4906
4874
                preProcessFile(node,folder,filecount)
4987
4955
                fatalError("The info.xml file (%s) doesn't look right" % os.path.join(folder,"info.xml"))
4988
4956
            title = expandItemText(infoDOM,"%title",1,0,0,0,0)
4989
4957
 
4990
 
            # convert to ascii and truncate to 32 chars
4991
 
            title = unicodedata.normalize('NFKD', title).encode('ASCII', 'ignore')
4992
 
            title = title[:32]
 
4958
            # replace all non-ascii-characters
 
4959
            title.encode('ascii', 'replace').decode('ascii', 'replace')
 
4960
            title.strip()
 
4961
            # replace not-allowed characters
 
4962
            index = 0
 
4963
            title_new = ''
 
4964
            while (index < len(title)) and (index<=7):
 
4965
                if title[index].isalnum and title[index] != ' ':
 
4966
                    title_new += title[index]
 
4967
                else:
 
4968
                    title_new += '_'
 
4969
                index = index + 1
 
4970
            title = title_new.upper()
 
4971
            if len(title) < 1:
 
4972
                title = 'UNNAMED'
4993
4973
 
4994
4974
            #Create the DVD ISO image
4995
4975
            if docreateiso == True or mediatype == FILE: