You can make a difference in the Apple Support Community!

When you sign up with your Apple Account, you can provide valuable feedback to other community members by upvoting helpful replies and User Tips.

Looks like no one’s replied in a while. To start the conversation again, simply ask a new question.

EyeTV with Commercial Skipping HD DVR Server

I use EyeTV HD and Turbo.264 HD to record and transcode h.264 shows for playback on a Mac, Apple TV, iPad, iPhone. I also use a self-modified version of etvcomskip to detect and mark commercials, which are then automatically skipped at playback. This makes tv viewing a lot more pleasurable and efficient, and is especially helpful controlling advertiser access to children. In case this is useful to others, I've outlined the steps here:


  1. Eric Kaashoek's website Comskip and download his HD-capable Comskip software. "Commercial" commercial-skippingcompanies (ReplayTV, TiVo, Dish, etc.) are quickly sued out of existence or into submission, even if they simply provide a basic "30-second skip" feature. Comskip is open source beerware that you can download, install, and use yourself, and you can't sue anyone for publishing source code. And rather than providing a simple 30-second skip feature, it detects, marks, and provides that capability for automatic commercial skipping.
  2. Comskip a Windows executable, so you'll need WINE (WINdows Emulator) on OS X to run it. First, download and install Xcode (free from the Apple App store), then download and install and install Macports, then in Terminal, run "sudo port selfupdate; sudo port install wine-devel". Finally, make sure that /Applications/Utilities/X11.app is added to your list of applications to run at login (WINE uses X11 to display Windows windows). Yes, this is windows emulation, but on a half-decent box you'll see that commercial skipping runs at around twice real-time for h.264 HD recordings.
  3. Download and install etvcomskip (and PyeTV if you want EyeTV to work with Front Row). The 2010 version of etvcomskip doesn't work with Comskip's latest HD capabilities, and the latest Comskip mpeg libraries do not allow live tv processing, so install these files to get everything working. Once you done this, you'll have a commercial-skipping HD DVR box on your Mac that can stream to Apple TV, iOS, or export to iTunes.

Comskip software

This lives in the directory /Library/Application Support/ETVcomskip.


Edit the file ./comskip/comskip.ini to use these HD-tuned settings, tailored for US cable:


detect_method=127;1=black frame, 2=logo, 4=scene change, 8=fuzzy logic, 16=closed captions, 32=aspect ration, 64=silence, 128=cutscenes, 255=all
max_avg_brightness=21;maximum average brightness for a dim frame to be considered black (scale 0 to 255) 0 means autosetting
non_uniformity=50; Set to 0 to disable cutpoints based on uniform frames
max_volume=20; any frame with sound volume larger than this will not be regarded as black frame
logo_at_bottom=1; Set to 1 to search only for logo at the lower half of the video, do not combine with subtitle setting
intelligent_brightness=1; Set to 1 to use a USA specific algorithm to tune some of the settings, not adviced outside the USA

volume_slip=150

output_dvrmstb=0; Set to 1 if you're running DVRMS-Toolbox
live_tv=0; set to 1 if you use parallelprocessing and need the output while recording
live_tv_retries=4; change to 16 when using live_tv in BTV, used for mpeg PS and TS


Edit the file ./MarkCommercials.app/Contents/Resources/MarkCommercials.py to use WINE to run comskip.exe nicely. Grep for these changes:


EyeTV.launch()


msg = 'Error: unable to communicate with %s\n' % options.app


#cmd = '"/Library/Application Support/ETVComskip/Wine.app/Contents/Resources/bin/wine" "/Library/Application Support/ETVComskip/comskip/comskip.exe" --ini="/Library/Application Support/ETVComskip/comskip/comskip.ini" "%s"' % MpgFile

# MacPorts 64-bit wine

#cmd = '"/Applications/Wine.app/Contents/Resources/bin/wine" "/Library/Application Support/ETVComskip/comskip/comskip.exe" --ini="/Library/Application Support/ETVComskip/comskip/comskip.ini" "%s"' % MpgFile

cmd = '"/opt/local/bin/wine" "/Library/Application Support/ETVComskip/comskip/comskip.exe" --ini="/Library/Application Support/ETVComskip/comskip/comskip.ini" "%s"' % MpgFile


# nice the wine command

cmd = "/usr/bin/nice -n 14 " + cmd


EyeTV software

EyeTV uses the triggered AppleScripts RecordingStarted and RecordingDone in the directory /Library/Application\ Support/EyeTV/Scripts/TriggeredScripts. Open these using the AppleScript Editor and use these scripts instead. You will probably have to Save As... on your desktop, then copy the updated script back into the correct directory to avoid permissions issues.


RecordingStarted.scpt


on RecordingStarted(recordingID)

delay 10

-- comskip81 uses ffmpeg and does not support live tv; put this in RecordingDone.scpt

-- set cmd to "export DISPLAY=:0.0; /usr/bin/nice -n 5 '/Library/Application Support/ETVComskip/MarkCommercials.app/Contents/MacOS/MarkCommercials' --log " & recordingID & " &> /dev/null &"

-- display dialog cmd

-- set cmd to "env > /tmp/etv_test.log &"

-- do shell script cmd


--disable this if you do not want a logfile written

write_to_file((short date string of (current date) & " " & time string of (current date)) & "Recording Started run for ID: " & recordingID & (ASCII character 13), (path to "logs" as string) & "EyeTV scripts.log", true)

end RecordingStarted


on write_to_file(this_data, target_file, append_data)

--from http://www.apple.com/applescript/sbrt/sbrt-09.html

try

set the target_file to the target_file as string

set the open_target_file to open for access file target_file with write permission

if append_data is false then set eof of the open_target_file to 0

write this_data to the open_target_file starting at eof

close access the open_target_file

return true

on error

try

close access file target_file

end try

return false

end try

end write_to_file

RecordingDone.scpt


-- Run the python MarkCommercials script for the given recording

-- this must be run with the RecordingStarted script

-- it will check if there were multiple PIDs for the recording and runs MarkCommercials for each pid

-- requires updated MarkCommercials which allows specifying the pid

-- by Ben Blake, September 2009


-- modified for latest Comskip, which cannot be run until after recording is finished; waits for Turbo.264 HD to stop running as well

-- S.T.Smith


global LogMsg


on RecordingDone(recordingID)


set ProcessName to "Elgato H.264 Decoder"

set DelayTime to 60

set MaxDelays to 4 * 60 -- four hours


-- delay until the process slows down or stops running

repeat MaxDelays times

delay DelayTime -- delay at least once to give it a chance to start

set pcpu to CPUPercentage(ProcessName)

if pcpu is equal to "" or pcpu < 2.0 then exit repeat -- break out of delay loop if it's not running

end repeat


delay 10

-- comskip81 uses ffmpeg and does not support live tv; take this from RecordingStarted.scpt

set cmd to "export DISPLAY=:0.0; /usr/bin/nice -n 5 '/Library/Application Support/ETVComskip/MarkCommercials.app/Contents/MacOS/MarkCommercials' --log " & recordingID & " &> /dev/null &"

-- display dialog cmd

-- set cmd to "env > /tmp/etv_test.log &"

do shell script cmd


set LogMsg to ""

CheckMultiplePIDs(recordingID)


--disable this if you do not want a logfile written

if (count of LogMsg) > 0 then

write_to_file((short date string of (current date) & " " & time string of (current date)) & LogMsg & (ASCII character 13), (path to "logs" as string) & "EyeTV scripts.log", true)

end if

end RecordingDone


-- testing code: this will not be called when triggered from EyeTV, but only when the script is run as a stand-alone script

on run

tell application "EyeTV.app"

set rec to «class Unqu» of item 1 of every «class cRec»


my RecordingDone(rec)

end tell

end run


-- compute the percentage CPU used by ProcessName

on CPUPercentage(ProcessName)

set ProcessPS to do shell script ("ps -axwwc | grep '" & ProcessName & "' | grep -v grep || true")

if ProcessPS is not equal to "" then

set ProcessID to word 1 of ProcessPS

set ProcessPS to do shell script ("ps -xwwco pid,ppid,%cpu -p " & ProcessID & " | tail -1")

set ProcessCPU to word 3 of ProcessPS

return ProcessCPU as number

else

return ""

end if

end CPUPercentage


on CheckMultiplePIDs(recordingID)

--check if there are multiple Video PIDs in the file


tell application "EyeTV.app"

set input_text to my read_from_file((path to "logs" as string) & "ETVComskip" & ":" & recordingID & "_comskip.log")

if (count of (input_text as string)) > 0 then

set logdata to every paragraph of input_text

set logdata_lastrow to (item ((count of logdata) - 1) of logdata) as string


if (items 1 thru 19 of logdata_lastrow) as string = "Video PID not found" then

--multiple Video PIDs, rerun MarkCommercials until successful


set recrdingIDInteger to recordingID as integer

set rec to «class cRec» id recrdingIDInteger

set LogMsg to "RecordingDone found multiple PIDs for recording ID: " & recordingID & ", Channel " & («class Chnm» of rec) & " - " & («class Titl» of rec)


set PIDs to (items 44 thru ((count of logdata_lastrow) - 2) of logdata_lastrow) as string

set delims to AppleScript's text item delimiters

set AppleScript's text item delimiters to ", "

set PID_List to {}

set PID_List to every word of PIDs

set AppleScript's text item delimiters to delims


repeat with pid in PID_List

my launchComSkip(recordingID, pid)

repeat while (my mcIsRunning())

delay 5

end repeat

end repeat


end if

end if

end tell

end CheckMultiplePIDs


on read_from_file(target_file)

--return the contents of the given file

set fileRef to (open for access (target_file))

set txt to (read fileRef for (get eof fileRef) as «class utf8»)

close access fileRef

return txt

end read_from_file


on write_to_file(this_data, target_file, append_data)

--from http://www.apple.com/applescript/sbrt/sbrt-09.html

try

set the target_file to the target_file as string

set the open_target_file to open for access file target_file with write permission

if append_data is false then set eof of the open_target_file to 0

write this_data to the open_target_file starting at eof

close access the open_target_file

return true

on error

try

close access file target_file

end try

return false

end try

end write_to_file


on launchComSkip(recID, pid)

if pid = "" then

set cmd to "export DISPLAY=:0.0; /usr/bin/nice -n 5 '/Library/Application Support/ETVComskip/MarkCommercials.app/Contents/MacOS/MarkCommercials' --force --log " & recID & " &> /dev/null &"

else

set cmd to "export DISPLAY=:0.0; /usr/bin/nice -n 5 '/Library/Application Support/ETVComskip/MarkCommercials.app/Contents/MacOS/MarkCommercials' --force --log " & recID & " --pid=" & pid & " &> /dev/null &"

end if


do shell script cmd

end launchComSkip


on mcIsRunning()

set processPaths to do shell script "ps -xww | awk -F/ 'NF >2' | awk -F/ '{print $NF}' | awk -F '-' '{print $1}' "

return (processPaths contains "MarkCommercials")

end mcIsRunning

<Links Edited By Host>

Mac mini Server (Mid 2010), Mac OS X (10.7.4), Lion Server, EyeTV HD, Turbo.264 HD

Posted on Jun 4, 2012 7:57 AM

Reply
144 replies

Oct 13, 2012 6:35 AM in response to Brandon Riffel

Yes, every step works great in Mountain Lion and previous OS X versions. A Turbo.264 HD dongle isn't necessary (I believe), as I wrote the RecordingDone script above so that commercial marking waits for this process to complete:


set ProcessName to "Elgato H.264 Decoder"


I believe that EyeTV runs this whether a Turbo.264 dongle is attached or not. Someone without a dongle—please confirm that this is correct. If that process isn't there, or isn't running at more than 2 percent CPU load, then commercial marking kicks in.


That said, I sure need a dongle for a mid-2010 Mac Mini, and though the latest Mac Mini probably wont see major speed improvements from a dongle, it's nice to offload transcoding from the CPU and save it for other major tasks, like running a server and recording new shows. Elgato may be exploiting the GPU on newer models, but I've not heard this.


An EyeTV HD box can be set up to save all recorded shows for streaming to iPad (720p). If you do this, then export "iPad" to iTunes (automatically or manually), then EyeTV will just copy this file without an additional transcoding step. Commercial marks in .edl files are cut out at the transcoding step. I've found that it's better to add chapter headings to h.264 files rather than delete content automatically. The steps look like:


Record -> Transcode -> Mark Commercials [ -> Export to iTunes]


Finally, I'd like to remind people to ask Elgato to add chapter navigation to their iOS streaming app, which will remove the extra iTunes step in many cases. Submit a ticket and make the feature request: http://tickets.kb.elgato.com/?language=en-us

Oct 13, 2012 1:35 PM in response to essandess

I have an HDHomeRun which outputs MPEG-2. The process that runs on my machine from EyeTV is "Elgato MPEG-2 Decoder" so I had to tweak the script to check that process for pausing to wait for the export to finish.


Below is the MarkCommercials.py with Growl fixed up. I know it works with Growl 2.0 but I think it should work back to 1.3. The script has to be called with --growl on the command line.


I also added a --m4vonly that will just chapter the m4v files on stuff that has been previously marked.


This is the first time I've coded in python, it all works but it might be a tad crude.

#!/usr/bin/env python # # MarkCommercials.py, EyeTV3 version # # Copyright (c) 2008, Jon A. Christopher # Copyright (c) 2008, TeamSTARS Dick Gordon and Rick Kier # Licensed under the GNU General Public License, version 2 # # # Run comskip on the specified file and replace the markers in the .eyetvr # file with the new markers. # # if no arguments show id, recording name... # # If argument is 'all', process all recordings which don't # have markers and do not match any exclude information from the cfg file. # # If argument is'forceall', process all recordings except those that match # any exclude information in the cfg file. # # Otherwise, argument is treated as an EyeTV recording id, and that # recording is processed if it is not excluded and it does NOT have any markers. # # To be done: # exporting - not needed?? # exclude channels # Issue: some channels are 0 # exclude titles # exclude station names # Issue: some station names are blank # Catch ^c when in c program - comskip throws SIGINT's away?? (see mpeg2dec.c) # Catch ^c when in python program - coded # EXCLUDED_TITLES and EXCLUDED_CHANNELS are NOT empty lists # Handle multiple video pids. # Added argument for PID - Ben Blake September 2009 # STS # Added macports wine, nice-ness, mp4chaps chapters headings at commercials import sys, os, string, os.path import time import math import traceback from optparse import OptionParser from ConfigParser import SafeConfigParser from os import listdir from os.path import isfile, join # Exit Codes # Everything worked ok successExitCode = 0 # Unable to import appscript importExitCode = 1 # Unable to find the recoring specified noRecordingExitCode = 2 # Error getting recordings from EyeTV getRecordingsErrorExitCode = 3 # Unknown exit code from comskip unknownComskipErrorExitCode = 4 # Error when accessing plist file accessPlistFileErrorExitCode = 5 # Error when accessing config file accessConfigFileErrorExitCode = 6 # Keyboard interrupt (^c) keyboardInterruptExitCode = 7 # Unable to communicate with the application communicationsErrorExitCode = 8 # provided with appscript package try: import aem from appscript import * except ImportError, e: sys.stderr.write('Error: importing appscript\n%s\n' % e) sys.exit(importExitCode) version = '0.4.0' # Cfg file definitions and variables userSectionName = 'User Section' listDelimiterName = 'LIST_DELIMITER' excludedTitlesName = 'EXCLUDED_TITLES' excludedChannelsName = 'EXCLUDED_CHANNELS' excludedStationNamesName = 'EXCLUDED_STATION_NAMES' excludedTitles = [] excludedChannels = [] excludedStationNames = [] # General variables options = None args = None recordingCount = 0 comskipLogPathName = None log = None growl = None eyeTV = None pathToComskip = None nameOfComskip = 'comskip' comskipLocations = ['.', r'/Library/Application Support/ETVComskip'] # for debugging. when False, will not actually run comskip, but will do everything else RUN_COMSKIP = True # Get the executable directory ETVComskipDir = os.path.abspath(os.path.dirname(__file__)) # Growl support commercialStart = 'Start' commercialStartDescription = 'Start detecting commercials' commercialStop = 'Stop' commercialStopDescription = 'Stop detecting commercials' programName = 'Mark Commercials' allNotificationsList = [commercialStart, commercialStop] def InitGrowl(): """docstring for InitGrowl""" global growl global allNotificationsList # Should we use growl? if not options.growl: # No return growl = app('Growl') enabledNotificationsList = allNotificationsList WriteToLog('Registering with growl\n') try: growl.register(as_application=programName, all_notifications=allNotificationsList, default_notifications=enabledNotificationsList) except Exception, e: WriteToLog('Error: registering with growl\n %s\n' % e) growl = None def sendGrowlNotification(name, title, description): """docstring for sendGrowlNotification""" # Send a Notification... if growl is not None: WriteToLog('Sending notification via growl (%s, %s, %s)\n' % (programName, title,description)) try: growl.notify(with_name=name, title=programName, description=description, application_name=programName) except Exception, e: WriteToLog('Error: growl notify\n %s\n' % e) # Create the log file def GetLog(name=None): """docstring for GetLog""" global log global comskipLogPathName # Should we log? if not options.log: return # Is the log directory created? fullPath = os.path.expanduser('~/Library/Logs/ETVComskip') if not os.path.isdir(fullPath): # No, create it. os.mkdir(fullPath) # Create the log if name is None: name = time.strftime('%m-%d-%Y %H-%M-%S') comskipLogPathName = os.path.join(fullPath, name + '_comskip.log') log = open(os.path.join(fullPath, name + '.log'), 'w') def WriteToLog(message): """docstring for WriteToLog""" if options.log: if type(message) == type(u""): message=message.encode("utf-8") log.write('%s - %s' % (time.asctime(), message)) log.flush() def CheckForApplicationCommunications(retries=3): """docstring for CheckForApplicationCommunications""" global EyeTV # launch the application EyeTV.launch() WriteToLog('Checking communications to %s with %d retries\n' % (options.app, retries)) for attempt in range(retries): try: # Get the recordings EyeTV.recordings.get() # It worked - break out of here WriteToLog(' Attempt %d worked\n' % (attempt + 1)) break except Exception, e: WriteToLog(' Attempt %d failed\n %s\n' % ((attempt + 1), e)) EyeTV = app(options.app) time.sleep(0.5) continue else: msg = 'Error: unable to communicate with %s\n' % options.app WriteToLog(msg) sys.stderr.write(msg) sys.exit(communicationsErrorExitCode) def GetRecordings(retries=0): """docstring for GetRecordings""" global EyeTV WriteToLog('Getting recordings\n') try: recordings = EyeTV.recordings.get() except Exception, e: msg = 'Error: unable to get recordings\n%s\n' % e WriteToLog(msg) sys.stderr.write(msg) sys.exit(getRecordingsErrorExitCode) WriteToLog('Recordings: %s\n' % recordings) return recordings # Possibly run comskip and return the name of a plist file with commercial markers in it def GetPlistFile(etvr_file, run_comskip=True): FileDir = os.path.dirname(etvr_file) dir, fil = os.path.split(etvr_file) FileRoot, ext = os.path.splitext(fil) MpgFile = FileRoot + ".mpg" PlistFile = FileRoot + ".edl" #cmd = '"/Library/Application Support/ETVComskip/Wine.app/Contents/Resources/bin/wine" "/Library/Application Support/ETVComskip/comskip/comskip.exe" --ini="/Library/Application Support/ETVComskip/comskip/comskip.ini" "%s"' % MpgFile # MacPorts 64-bit wine #cmd = '"/Applications/Wine.app/Contents/Resources/bin/wine" "/Library/Application Support/ETVComskip/comskip/comskip.exe" --ini="/Library/Application Support/ETVComskip/comskip/comskip.ini" "%s"' % MpgFile cmd = '"/opt/local/bin/wine" "/Library/Application Support/ETVComskip/comskip/comskip.exe" --ini="/Library/Application Support/ETVComskip/comskip/comskip.ini" "%s"' % MpgFile if options.pid <> "": cmd += " --pid=" + options.pid outputName = '/dev/null' if options.log: cmd += ' > %s 2>&1' % comskipLogPathName else: cmd += ' > %s 2>&1' % '/dev/null' if options.verbose: cmd += ' --verbose=%d' % options.verbose # nice the wine command cmd = "/usr/bin/nice -n 14 " + cmd WriteToLog('Changing directory to %s\n' % FileDir) os.chdir(FileDir) if run_comskip: #get the show name from the Directory Path showName=os.path.splitext(os.path.basename(FileDir))[0] # Notify the user sendGrowlNotification(commercialStart, commercialStart + " " + showName, commercialStartDescription + " on " + showName) # TBD stop comskip when ^c happens if not options.m4vonly: WriteToLog('Running: %s\n' % cmd) rc = os.system(cmd) else: WriteToLog('Skipped Comm Search, attempting to just add m4v Markers.') rc=0 # Add the Comskip information as chapters to all m4v files mp4chaps_all_m4v(FileDir) # Notify the user sendGrowlNotification(commercialStop, commercialStop + " " + showName, commercialStopDescription + " on " + showName) WriteToLog('Return code is: %d, 0x%x\n' % (rc, rc)) errorCode = (rc >> 8) & 0xff WriteToLog('Error code is: %d, 0x%x\n' % (errorCode, errorCode)) # Error code: # 3 = no Video pid found # 2 = Can't open the mpeg2 file TBD # 1 = Commercials found # 0 = Commercials not found if errorCode == 2: msg = 'Unable to open mpeg2 file return from "comskip": %d\n' % errorCode WriteToLog(msg) sys.stderr.write(msg) return None elif errorCode == 3: msg = 'No video pid found return from "comskip": %d\n' % errorCode WriteToLog(msg) sys.stderr.write(msg) return None elif errorCode == 1: WriteToLog('Commercials found by comskip\n') return PlistFile elif errorCode == 0: WriteToLog('No commercials found by comskip\n') return None else: msg = 'Error: unknown error code from comskip: %d, assuming it worked.\n' % errorCode WriteToLog(msg) return PlistFile # return start and ending times for the given line def TimeChop(line): fields = line.split("\t") start = (float(fields[0])) end = (float(fields[1])) return (start,end) # given a plist file, return a markers array suitable for adding to a recording def GetMarkersArray(PlistFile): try: file = open(PlistFile) lines = file.readlines() file.close() except Exception, e: msg = 'Error: accessing %s\n%s\n' % (PlistFile, e) WriteToLog(msg) sys.stderr.write(msg) sys.exit(accessPlistFileErrorExitCode) WriteToLog('Plist file contents: %s\n' % lines) markers=[] for line in lines: WriteToLog("Processing plist file line: '%s'\n" % line) start,end = TimeChop(line) WriteToLog('Adding marker, start: %d, end: %d\n' % (start, end)) marker = {} marker['position'] = start marker[aem.AEType('leng')] = end - start markers.append(marker) return markers def ProcessRecording(recording, run_comskip): global recordingCount channel = recording.channel_number() title = recording.title() stationName = recording.station_name() recordingCount += 1 msg = '%2d. Processing "%s" on [%s] channel [%s]...' % (recordingCount, title, stationName, channel) WriteToLog('%s\n' % msg) print msg.encode("utf-8") # Should excludes be allowed? if not options.noexclude: # Yes, Is this one allowed? # User can exclude titles, channels and station names # Channel msg=' Channel: %s' % channel print msg.encode("utf-8"), if str(channel) in excludedChannels: WriteToLog('Skipped due to channel match\n') print ' skipped' return print ', not skipped' # Title msg=' Title: %s' % title print msg.encode("utf-8"), if title in excludedTitles: WriteToLog('Skipped due to title match\n') print ' skipped' return print ', not skipped' # Station name msg=' Station name: %s' % stationName print msg.encode("utf-8"), if stationName in excludedStationNames: WriteToLog('Skipped due to station name match\n') print ' skipped' return print ', not skipped' # Get its path etvr_path = recording.location.get().path WriteToLog('Path to recording is %s\n' % etvr_path) # get the plist file for this recording, and make a markers array for it Plist = GetPlistFile(etvr_path, run_comskip) # Did we get a plist file? if Plist is not None: # Yes, convert it. markers = GetMarkersArray(Plist) # and finally, set them WriteToLog('Setting markers on recording\n') markers_string = str(markers) WriteToLog('Adding marker: %s\n' % (markers_string)) recording.markers.set(markers) mp4chaps = '/opt/local/bin/mp4chaps' def sec2hhmmss(secs): """Convert seconds to string HH:MM:SS.SSS format.""" rem = secs/3600 hh = int(rem) rem = (rem-hh)*60 mm = int(rem) rem = (rem-mm)*60 ss = int(rem) rem = (rem-ss) rem = '%.3f' % rem # millisecond precision rem = rem.replace('0.','.') return '%02d:%02d:%02d%s' % (hh,mm,ss,rem) def split_whitespace_nolibs(str): """Split a string by whitespace without using re or shlex libraries..""" strs = filter(None,str.split('\t')) strs = map(lambda s: s.split(' '),strs) strs = filter(None,[item for sublist in strs for item in sublist]) return strs def edl2mp4chaps(edl_file,file): """Convert an edl file into an mp4chaps file.""" txt_file = file.replace('.m4v','.chapters.txt') ftxt = open(txt_file,'w') comskipno = 0 comskipchapno = 0 lines = [line.strip() for line in open(edl_file)] for line in lines: times = map(float,split_whitespace_nolibs(line)) if (comskipno == 0 and times[0] != 0.0): comskipno += 1 if (len(times) < 2 or times[2] == 0.0): if (times[0] != 0.0): ftxt.write('%s Chapter %d End\n' % (sec2hhmmss(times[0]),comskipno)) else: ftxt.write('00:00:00.000 Beginning\n') comskipno += 1 ftxt.write('%s Chapter %d Start\n' % (sec2hhmmss(times[1]),comskipno)) else: # never seen this case, but here for logical consistency comskipchapno += 1 if (times[0] != 0.0): ftxt.write('%s Chapter %d Start\n' % (sec2hhmmss(times[0]),comskipchapno)) else: ftxt.write('00:00:00.000 Beginning\n') ftxt.write('%s Chapter %d End\n' % (sec2hhmmss(times[1]),comskipchapno)) ftxt.close() return def mp4chaps_all_m4v(dir): """Apply an edl file's entries to all m4v files in a directory.""" os.chdir(dir) edl_file = "" files = [ file for file in listdir(dir) if isfile(join(dir,file)) ] for file in files: if file.find('.edl') != -1: edl_file = file break if edl_file != "" and os.path.isfile(mp4chaps): for file in files: if file.find('.m4v') != -1: # remove all chapters cmd = mp4chaps + ' -r ' + file + ' > /dev/null 2>&1' rc = os.system(cmd) # create chapter file edl2mp4chaps(edl_file,file) # import chapters cmd = mp4chaps + ' -i ' + file + ' > /dev/null 2>&1' rc = os.system(cmd) return def main(): global options global args global excludedTitles global excludedChannels global excludedStationNames global log global EyeTV # Do the options usage = "usage: %prog [options] [RECORDING-ID | 'all' | 'forceall']" parser = OptionParser(usage=usage, version=version) parser.add_option("--noexclude", action="store_true", dest="noexclude", default=False, help="Do NOT exclude recordings specified in cfg file, default=%default") parser.add_option("--force", action="store_true", dest="force", default=False, help="Force commercial marking on specified RECORDING-ID. Allows marking when markers already exist, default=%default") parser.add_option("--growl", action="store_true", dest="growl", default=False, help="Enable growl notification, default=%default") parser.add_option("--log", action="store_true", dest="log", default=False, help="Enable logging, default=%default") parser.add_option("--app", dest="app", default='EyeTV', help="Specify EyeTV application name, default=%default") parser.add_option("--verbose", type='int', dest="verbose", default=0, help="Verbosity level, 0-10, default=%default") parser.add_option("--pid", dest="pid", default='', help="Specify the Video PID, default=%default") parser.add_option("--m4vonly", dest="m4vonly", default=False, help="Only chapter m4v files that have already had commercials marked, don't try to mark commercials. default=%default") (options, args) = parser.parse_args() if len(args): name = args[0] else: name = None GetLog(name=name) WriteToLog('%s, %s starting\n' % (sys.argv[0], version)) WriteToLog('Command line: %s\n' % sys.argv) WriteToLog('Application name: %s\n' % options.app) print '\t\t%s\t%s\n' % (os.path.splitext(os.path.basename(sys.argv[0]))[0], version) # Get the app EyeTV = app(options.app) # Use growl notifications InitGrowl() # Get our configuration file & data configInput = SafeConfigParser() try: cfgFilesRead = configInput.read([os.path.join(os.path.dirname(sys.argv[0]), 'MarkCommercials.cfg'), os.path.expanduser('~/Library/Application Support/ETVComskip/MarkCommercials.cfg')]) except Exception, e: msg = 'Error: reading configuration file\n%s\n' % e WriteToLog(msg) sys.stderr.write(msg) sys.exit(accessConfigFileErrorExitCode) WriteToLog('Cfg files read: %s\n' % cfgFilesRead) if cfgFilesRead: # Process the user's section if configInput.has_section(userSectionName): # Process the user's section # Get the delimiter listDelimiter = configInput.get(userSectionName, listDelimiterName) if configInput.has_option(userSectionName, excludedChannelsName): for channel in configInput.get(userSectionName, excludedChannelsName).split(listDelimiter): excludedChannels.append(channel) if configInput.has_option(userSectionName, excludedTitlesName): for title in configInput.get(userSectionName, excludedTitlesName).split(listDelimiter): excludedTitles.append(title) if configInput.has_option(userSectionName, excludedStationNamesName): for title in configInput.get(userSectionName, excludedStationNamesName).split(listDelimiter): excludedStationNames.append(title) WriteToLog('List Delimiter: %s\n' % listDelimiter) WriteToLog('Excluded Channels: %s\n' % excludedChannels) WriteToLog('Excluded Titles: %s\n' % excludedTitles) WriteToLog('Excluded Station names: %s\n' % excludedStationNames) # Test communications with application CheckForApplicationCommunications() # Get the location of the commercial skipper #findComskip() # Show the IDs and program names when there are no arguments # replace any non ascii characters with ? if len(args) == 0: for rec in GetRecordings(): programName = os.path.split(os.path.splitext(os.path.dirname(rec.location.get().path))[0])[1] outputName = '' for char in programName: # Insure the character is ascii if ord(char) <= 127: outputName += char else: outputName += '?' msg = ' %d = [%s], [%s], [%s]' % (rec.unique_ID.get(), outputName, rec.channel_number(), rec.station_name()) WriteToLog('%s\n' % msg) print msg.encode("utf-8") return successExitCode if args[0] == "all" or args[0] == "forceall": # batch mode, process all recordings without markers recs = GetRecordings() for rec in recs: markerCount = len(rec.markers.get()) WriteToLog('Marker count: %d\n' % markerCount) if markerCount == 0 or args[0] == "forceall": ProcessRecording(rec, RUN_COMSKIP) else: # triggered mode, process just the listed recording recs = GetRecordings() recordingRequested = int(args[0]) for rec in recs: if rec.unique_ID() == recordingRequested: WriteToLog('Found recording %d\n' % recordingRequested) break else: msg = 'Error: unable to find recording %d\n' % recordingRequested WriteToLog(msg) sys.stderr.write(msg) sys.exit(noRecordingExitCode) markerCount = len(rec.markers.get()) WriteToLog('Marker count: %d\n' % markerCount) # Recording already have markers? if markerCount == 0 or options.m4vonly: # No try: ProcessRecording(rec, RUN_COMSKIP) except Exception,e: exc_type, exc_value, exc_traceback = sys.exc_info() WriteToLog(repr(traceback.format_exception(exc_type, exc_value,exc_traceback))) # Is the recording already marked but the user wants it done again? elif markerCount != 0 and options.force: # Yes WriteToLog('Recording already marked - use forcing with --force option\n') ProcessRecording(rec, RUN_COMSKIP) else: # Recording already maked and user doesn't want it done again msg = 'Recording previously marked' WriteToLog('%s\n' % msg) print ' ', print msg.encode("utf-8") return successExitCode if __name__ == '__main__': ''' Call main ''' try: exitStatus = main() except KeyboardInterrupt, e: msg = 'Error: %s\n' % e WriteToLog(msg) sys.stderr.write(msg) sys.exit(keyboardInterruptExitCode) pass WriteToLog('Exiting\n') sys.exit(exitStatus)

Oct 18, 2012 8:39 PM in response to essandess

I have been super excited to attempt to get this working on my install of EyeTV. The issue that I'm running into is that when I attempt to either run "MarkCommercials all" from the command line the result I get is this:

1. Processing "Castle" on [KSTP HDTV] channel [431]...

Channel: 431 , not skipped

Title: Castle , not skipped

Station name: KSTP HDTV , not skipped

Error: accessing 00000000162cf6e4.edl

(2, 'No such file or directory')


However when I run comskip directly from the command line using the following command (running from inside the recording's package):

/opt/local/bin/wine /Library/Application\ Support/ETVComskip/comskip/comskip.exe --ini=/Library/Application\ Support/ETVComskip/comskip/comskip.ini 00000000162cda88.mpg

There is a text file that is output named "00000000162cda88.txt". I've also been having issues with the program crashing but I'm betting that was one of my recordings being funky. Any thoughts on how to go about getting this to work? I'm getting the same result off of the RecordingDone.scpt as well. Any help would be appreciated. Thanks!

Oct 19, 2012 6:58 AM in response to sheldoa

@sheldoa


Looks like a mismatch between the .mpg file name and the .edl file name, whose root name should be identical. Troubleshooting:


  1. Cut-and-paste--posting-error on your part, or is this real?
  2. Is this a problem for all recordings or a single recording? To test (using @gardnern's MarkCommercials.py above):
    • $ /Library/Application\ Support/ETVComskip/MarkCommercials.app/Contents/MacOS/MarkCommercials # prints out all your EyeTV recordID's
    • $ /Library/Application\ Support/ETVComskip/MarkCommercials.app/Contents/MacOS/MarkCommercials <recordID> # rerun comskip
    • $ /Library/Application\ Support/ETVComskip/MarkCommercials.app/Contents/MacOS/MarkCommercials --m4vonly=true <recordID>
    • $ /Library/Application\ Support/ETVComskip/MarkCommercials.app/Contents/MacOS/MarkCommercials all # mark 'em all!
  3. Use the command

    $ find /The/Full/POSIX/Path/to/Your/EyeTV\ Archive -name '00000000162cda88.mpg'

  4. Then look at this .eyetv's directories contents. It should look like this:


$ ls -1

0000000016206100.eyetvp

000000001630f938.edl

000000001630f938.exported_inodes.txt

000000001630f938.eyetvi

000000001630f938.eyetvr

000000001630f938.iPad.chapters.txt

000000001630f938.iPad.m4v

000000001630f938.log

000000001630f938.logo.txt

000000001630f938.mpg

000000001630f938.thumbnail.tiff

000000001630f938.tiff

000000001630f938.txt


@gardnern Thanks for the updated script! Works great on my system, and it's been nice to have the m4vonly option to test to improved functionality I've added.


@all interested: I've written script that allows automatic, asynchronous iTunes exports and commercial marking. I'm almost done testing them and will post soon to ETVComskip's googlecode page. These scripts transparently and automatically address all the issues discussed above: you can do exports or commercial marking in any order you want, or simultaneously, and both scripts take care of adding commercial skipping information to the iTunes files independently. There is an EyeTV ExportDone.scpt that saves all exported files' inode numbers to a new file called root-name.exported_inodes.txt (see above), then imports the .edl markings as h.264 chapters if there's a corresponding .edl file. And there's an updated MarkCommercials.py script that also imports .edl markings as h.264 chapters into all existing exports if there's a corresponding .exported_inodes.txt file. iTunes can and will rename and reorganize the exported files, and the python script finds whatever iTunes filenames that have the inode number saved by ExportDone.scpt. It all works asynchronously, and though I've only tested it on my iPad, I expect it to work with Apple TV and many individual iTunes and HTPC setups. So watch this space.

Oct 19, 2012 11:19 AM in response to gardnern

No. EyeTV takes care of all exporting. The (modified) ETVComskip setup simply does two things: (1) adds a .edl Edit Decision List file to the .eyetv directory for commercial skipping during EyeTV/Turbo.264/etc. playback; (2) adds the .edl cutpoints as chapters within the h.264 files created by EyeTV, whether in the EyeTV Archive or exported to iTunes.


It would be quite simple to modify EyeTV's RecordingDone script to export files to whichever location you would like to see them in. It would also be simple to copy part of the to-be-posted ExportDone AppleScript that remembers the inode information of each exported file, allowing MarkCommercials.py to asynchronously add .edl information to these exported files.


BTW, I tried Plex once but gave up on it because Plex kept using my 720p files (created for fast streaming) rather than the full 1080p HD recordings -- there didn't seem to be a way to tell it to use the best video available. Do you have Plex working well with EyeTV? How does this work? Is it really necessary to export files from EyeTV to Plex to avoid this problem?

Oct 19, 2012 11:39 AM in response to essandess

Actually after I asked I went on a bit of a research trip. Right now I'm using a Scanner written to add links to the playable file in an EyeTV package into Plex. This works very well and even grabs weird stuff I record that dosn't have Episode numbers on them, like PBS cooking episodes.


Primarily I'm interested in the commercial skipping working within Plex itself. Whil this doesn't appear to be an option playing the recorded .mpg file directly, perhaps it would work if I exported into the eyeTV recording package and then had Plex play the .m4v file instead.


The question is if Plex will respect the chapter marks. If it won't then I'd have to run Comskip first, then have EyeTV run an export which would leave out the flagged commercial sections.


I have glanced over a lot of discussions on the Plex forums concerning its use of the improper (lower quality) stream. I believe a lot of work has been done in this respect. I know there is now a place to define your preferred stream quality at least for web based myPlex videos. In their new web client you can also define the quality of stream you wish to receive.


If you haven't looked into Plex within the last 6 months I would encourage you to give the latest release a try. If I could get football to live broadcast through Plex with Pause/FF/Rewind working I probably wouldn't watch anything at all through EyeTV directly..

Dec 5, 2015 2:09 PM in response to essandess

I've posted new and improved ETVComskip modifications at the ETVComskip google code page.


These modifications allow the use of comskip for H.264 HD video and adds comskip information to EyeTV iTunes exports.


Comskip .edl information is added as chapters within the H.264 .m4v files exported by EyeTV and Turbo.264, providing a mobile Comskip solution: when the ads appear, skip to the next chapter. It avoids the problem of false detections by not deleting any program material.


The scripts above perform simple load balancing by making sure that transcoding and/or exports are done first, then Comskip is run, as well as setting a high UNIX nice value for the comskip process. A Turbo.264 HD dongle used to offload transcoding from the CPU may be used but is not necessary, as the RecordingDone script is written so that commercial marking waits for the process "Elgato H.264 Decoder" to complete before running Comskip. The steps look like:


Record -> Transcode [ -> Export to iTunes] -> Mark Commercials


Automatic, asynchronous, and transparent commercial marking of iTunes exports is performed. There is an EyeTV ExportDone.scpt that saves all exported files' inode numbers to a new file called root-name.exported_inodes.txt, then imports the .edl markings as h.264 chapters if there's a corresponding .edl file. And there's an updated MarkCommercials.py script that also imports .edl markings as h.264 chapters into all existing exports if there's a corresponding .exported_inodes.txt file. iTunes can and will rename and reorganize the exported files, and the python script finds whatever iTunes filenames that have the inode number saved by ExportDone.scpt. It all works asynchronously, and though I've tested it using an iPad, I expect it to work with Apple TV and many individual iTunes and HTPC setups.


Zip file contents:


ExportDone.scpt

MarkCommercials.py

RecordingDone.scpt

RecordingStarted.scpt

comskip.ini

readme-and-install.sh


Help string in readme-and-install.sh:


Installation:


1. Eric Kaashoek's website www.kaashoek.com/comskip/

and download his HD-capable Comskip software.


2. Install Xcode from the App Store and Macports from http://www.macports.org/.

For Mountain Lion, install Xquartz.


3. Install ETVComskip from code.google.com/p/etv-comskip/downloads/list.


4. Install Kaashoek's comskip files within the directory

/Library/Application\ Support/ETVComskip/comskip

Make sure that the ownership/group/permissions are set exactly the same

as the original ./comskip directory and files.


5. Download this zip file and check that your iTunes TV Shows directory

matches this setting at the beginning of ./MarkCommercials.py:

iTunes_TV_Shows = '~/Music/iTunes Media/TV Shows'

Edit ./MarkCommercials.py to match this, then run these commands as a sudoer:


# Necessary Macports

sudo port selfupdate

sudo port install wine-devel mp4v2


# Move these five files into their correct locations

sudo install -B .orig -b -m 0644 ./comskip.ini /Library/Application\ Support/ETVComskip/comskip/comskip.ini

sudo install -B .orig -b -m 0644 ./MarkCommercials.py /Library/Application\ Support/ETVComskip/MarkCommercials.app/Contents/Resources/MarkCommercials.py

sudo install -B .orig -b -m 0644 ./RecordingStarted.scpt /Library/Application\ Support/EyeTV/Scripts/TriggeredScripts/RecordingStarted.scpt

sudo install -B .orig -b -m 0644 ./RecordingDone.scpt /Library/Application\ Support/EyeTV/Scripts/TriggeredScripts/RecordingDone.scpt

sudo install -B .orig -b -m 0644 ./ExportDone.scpt /Library/Application\ Support/EyeTV/Scripts/TriggeredScripts/ExportDone.scpt


The AppleScript ExportDone.scpt is new; here is the new code to accomplish asynchronous comskip marking of EyeTV iTunes exports:


-- EyeTV ExportDone script to save exported file inode numbers as the text file filename.exported_inodes.txt and import .edl files as mp4 chapters


-- Copyright © 2012 Steven T. Smith <steve dot t dot smith at gmail dot com>, GPL


-- This program is free software: you can redistribute it and/or modify

-- it under the terms of the GNU General Public License as published by

-- the Free Software Foundation, either version 3 of the License, or

-- (at your option) any later version.

--

-- This program is distributed in the hope that it will be useful,

-- but WITHOUT ANY WARRANTY; without even the implied warranty of

-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

-- GNU General Public License for more details.

--

-- You should have received a copy of the GNU General Public License

-- along with this program. If not, see <http://www.gnu.org/licenses/>.



on ExportDone(recordingID)


set myid to recordingID as integer

set mp4chaps to "/opt/local/bin/mp4chaps"

set mp4chaps_suffix to ".chapters.txt"

set export_suffix to ".exported_inodes.txt"

set edl_suffix to ".edl"

set perl_suffix to ".pl"


tell application "EyeTV"

set myshortname to get the title of recording id myid

set eyetvr_file to get the location of recording id myid as alias

end tell


tell application "Finder"

-- Get EyeTV's root file names and paths for the recording

set eyetv_path to container of eyetvr_file as string

-- fix AppleScript's strange trailing colon issue for paths

if character -1 of eyetv_path is not ":" then set eyetv_path to eyetv_path & ":"

set eyetv_file to name of eyetvr_file

set eyetv_root to (RootName(eyetv_file) of me)

set edl_file to eyetv_path & eyetv_root & edl_suffix

set edl_file_posix to POSIX path of edl_file

set exported_inodes_file to eyetv_path & eyetv_root & export_suffix

end tell


-- give iTunes a chance to sync

delay 30 --if the script does not seem to work, try increasing this delay slightly.


tell application "iTunes"

set mytv to get the location of (the tracks of playlist "TV Shows" whose name is myshortname or artist is myshortname)

end tell


-- return if no exports match; this shouldn't happen!

if the (count of mytv) is less than 1 then return


tell application "Finder"

-- find the most recent export that isn't an open file

set mymp4 to item 1 of mytv

set mydate to modification date of mymp4

repeat with kk from 2 to count of mytv

if mydate is less than (modification date of item kk of mytv) and not my IsFileOpen(POSIX path of item kk of mytv) then

set mymp4 to item kk of mytv

set mydate to modification date of mymp4

end if

end repeat

set mymp4_posix to POSIX path of mymp4

-- safely quote any single quote characters for system calls: ' --> '"'"'

set mymp4_posix_safequotes to my replace_chars(mymp4_posix, "'", "'\"'\"'")

set itunes_path to container of mymp4 as string

-- fix AppleScript's strange trailing colon issue for paths

if character -1 of itunes_path is not ":" then set itunes_path to itunes_path & ":"

set itunes_file to name of mymp4

set itunes_root to (RootName(itunes_file) of me)


-- save the iTunes file inode to the exported files file "*.exported_inodes.txt"

-- find the exported file with the command: find . -type f -inum <inum>

set ef_handle to open for access exported_inodes_file with write permission

write (my FileInode(mymp4_posix) as string) & return to ef_handle starting at eof

close access ef_handle


-- return if no .edl file

if not (exists file edl_file) then return


-- add the mp4 chapters if the .edl file exists


-- define the mp4chaps chapter file

set itunes_chapter_file to (POSIX path of itunes_path) & itunes_root & mp4chaps_suffix


-- translate the .edl file into a mp4chaps chapter file using perl


set perlCode to "

#!/usr/bin/perl


########################################

# CONVERT EDL FILES TO MP4CHAPS FILES #

########################################


# Copyright © 2012 Steven T. Smith <steve dot t dot smith at gmail dot com>, GPL


# This program is free software: you can redistribute it and/or modify

# it under the terms of the GNU General Public License as published by

# the Free Software Foundation, either version 3 of the License, or

# (at your option) any later version.

#

# This program is distributed in the hope that it will be useful,

# but WITHOUT ANY WARRANTY; without even the implied warranty of

# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

# GNU General Public License for more details.

#

# You should have received a copy of the GNU General Public License

# along with this program. If not, see <http://www.gnu.org/licenses/>.


use strict;


my $edl_file = q{" & edl_file_posix & "};

my $txt_file = q{" & itunes_chapter_file & "};


sub sec2hhmmss {

my $rem = $_[0]/3600;

my $hh = int($rem);

$rem = ($rem - $hh)*60;

my $mm = int($rem);

$rem = ($rem - $mm)*60;

my $ss = int($rem);

$rem = ($rem - $ss);

$rem = sprintf(\"%.3f\",$rem); # millisecond precision

$rem =~ s/^0//;

return sprintf(\"%02d:%02d:%02d%s\",$hh,$mm,$ss,$rem);

}


open (EDL,$edl_file) || die(\"Cannot open edl file \" . $edl_file);

open (TXT,\">\",$txt_file) || die(\"Cannot open txt file \" . $txt_file);

my $line;

my @times;

my $comskipno = 0;

my $comskipchapno = 0;

print TXT \"00:00:00.000 Beginning\\n\";

while ($line = <EDL>) {

chomp $line;

# parse the space-delimited edl ascii times into an array of numbers

@times = split ' ', $line;

@times = map {$_+0} @times; # (unnecessarily) convert strings to numbers

$comskipno += 1 if ($comskipno == 0 && $times[0] != 0.0);

if ($#times < 2 || $times[2] == 0.0) {

if ($times[0] != 0.0) {

print TXT sprintf(\"%s Chapter %d End\\n\",sec2hhmmss($times[0]),$comskipno);

}

$comskipno++;

print TXT sprintf(\"%s Chapter %d Start\\n\",sec2hhmmss($times[1]),$comskipno);

} else {

# never seen this case, but here for logical consistency

$comskipchapno++;

if ($times[0] != 0.0) {

print TXT sprintf(\"%s Chapter %d Start\\n\",sec2hhmmss($times[0]),$comskipchapno);

}

print TXT sprintf(\"%s Chapter %d End\\n\",sec2hhmmss($times[1]),$comskipchapno);

}

}

close (EDL) ;

close (TXT) ;

"


-- define the perl script and run it and delete it

set perl_file to eyetv_path & eyetv_root & perl_suffix

-- safely quote any single quote characters for system calls: ' --> '"'"'

set perl_file_safequotes to my replace_chars(POSIX path of perl_file, "'", "'\"'\"'")


set pl_handle to open for access perl_file with write permission

set eof of pl_handle to 0

write perlCode & return to pl_handle

close access pl_handle

set perlRes to do shell script "perl '" & perl_file_safequotes & "' || true"

delete file perl_file


-- execute mp4chaps and delete the chapter file

-- remove any existing chapters

set mp4chapsRes to do shell script mp4chaps & " -r '" & mymp4_posix_safequotes & "' > /dev/null 2>&1 || true"

-- import the comskip chapters

set mp4chapsRes to do shell script mp4chaps & " -i '" & mymp4_posix_safequotes & "' > /dev/null 2>&1 || true"

-- delete the chapter file

delete file (itunes_path & itunes_root & mp4chaps_suffix)


end tell

end ExportDone


-- extract the root name of a file

on RootName(fname)

-- http://stackoverflow.com/questions/12907517/extracting-file-extensions-from-appl escript-paths

set root to fname as string

set delims to AppleScript's text item delimiters

set AppleScript's text item delimiters to "."

if root contains "." then set root to (text items 1 thru -2 of root) as text

set AppleScript's text item delimiters to delims

return root

end RootName


-- get the inode of a file

on FileInode(posix_filename)

-- safely quote any single quote characters for system calls: ' --> '"'"'

set posix_filename_safequotes to my replace_chars(posix_filename, "'", "'\"'\"'")

set fi to do shell script ("ls -i '" & posix_filename_safequotes & "' || true")

if fi is not equal to "" then

set fi to word 1 of fi

return fi as number

else

return ""

end if

end FileInode


-- test if a file is open

on IsFileOpen(posix_filename)

-- safely quote any single quote characters for system calls: ' --> '"'"'

set posix_filename_safequotes to my replace_chars(posix_filename, "'", "'\"'\"'")

set res to do shell script ("lsof '" & posix_filename_safequotes & "' > /dev/null 2>&1 && echo 'true' || echo 'false' || true")

if res is equal to "true" then

set res to true

else

set res to false

end if

return res

end IsFileOpen


-- string replacement

on replace_chars(this_text, search_string, replacement_string)

set delims to AppleScript's text item delimiters

set AppleScript's text item delimiters to the search_string

set the item_list to every text item of this_text

set AppleScript's text item delimiters to the replacement_string

set this_text to the item_list as string

set AppleScript's text item delimiters to delims

return this_text

end replace_chars



-- testing code: this will not be called when triggered from EyeTV, but only when the script is run as a stand-alone script

on run

tell application "EyeTV"

--set rec to unique ID of item 1 of recordings

-- for all your id's, run /Library/Application\ Support/ETVComskip/MarkCommercials.app/Contents/MacOS/MarkCommercials

set rec to 372308280

my ExportDone(rec)

end tell

end run

<Links Edited By Host>

Nov 8, 2012 12:44 AM in response to essandess

HI

thank you. your instructions were very helpful for me but I live in Europe and I don't have neither HD or turbo264. Are your changes to the standard version (edit markcommercials.py, the new scripts) useful for me? my etv comskip (standard version) marks well short program (below 1 and half hour) but not the longer ones (like movies).

if your changes are useful, could you explain better how to "edit markcommercials.py"? do I have to substitute the similar parts in the original file?

thank you

Nov 9, 2012 4:45 AM in response to fracnl14

The ETVComskip modifications allow commercial marking on HD content, so if you don't have an HD PVR, the original ETVComskip is what you want. However, the EyeTV script ExportDone.scpt above will mark commercials in iTunes exports whether they're HD or not, so that may be useful.


Also, if you're having issues with Comskip, try downloading the latest free version and swapping it in as described for the contributor version above—that has a good chance of resolving little problems.


Finally, google "os x text editor" for text editing questions.

Nov 15, 2012 4:24 PM in response to essandess

Hello,


Perhaps you can help me - I'm having a problem that initially was similar to sheldoa, i.e., that I was getting "No such file or directory" when running MarkCommercials from the command line. It doesn't appear to be the same problem, however, as when I look in my .eyetv file, I see no .edl file whatsoever. I came to the conclusion (correct me if I'm wrong here) that comskip didn't do it's job. So, I also tried running comskip from the command line:


/opt/local/bin/wine /Library/Application\ Support/ETVComskip/comskip/comskip.exe --ini=/Library/Application\ Support/ETVComskip/comskip/comskip.ini 0000000016536aa4.mpg


This fails with the error:


err:module:attach_process_dlls "winspool.drv" failed to initialize, aborting

err:module:LdrInitializeThunk Main exe initialization for L"Z:\\Library\\Application Support\\ETVComskip\\comskip\\comskip.exe" failed, status c0000005


Which leads me to believe I was right. It also seems like comskip is not functioning because wine itself is not starting. Does comskip itself create the .edl file within each .eyetv package?


I have carefully gone through the installation steps detailed in the readme, and have made sure I have the latest macports updates, the donor version of comskip, etc. XQuartz is installed and running, and wine-devel and mp4v2 and their dependencies install without error from macports. I also have copied your files from the zip as instructed. Is there something I'm missing?


Any help would be very much appreciated!


Cheers,

S


PS. This is Mountain Lion on a Mac Mini with my EyeTV Archive in a non-default location (on my external firewire Media volume)

Nov 15, 2012 5:13 PM in response to Ste88

Welcome to UNIX sysadmin. It's probably X11 related. Are you running XQuartz? (Add XQuartz to your login items.) Try these troubleshooting steps:


# X11 DISPLAY (bash) -- first user instance is :0, second is :1, and so on

export DISPLAY=:0.0


# X windows works?

xeyes


# wine works?

sudo port install winetricks

winetricks


# try launching some non-clippy DOS program

wine ~/.wine/dosdevices/c\:/windows/system32/wordpad.exe


If these basic things don't work, Comskip won't work either. If they do, check your ETV logs in ~/Library/Logs. Google any error messages for any of these steps.

EyeTV with Commercial Skipping HD DVR Server

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.