Wednesday, February 6, 2013

How to get EyeTV recordings into Plex

I like EyeTV, I have it set up with a Hauppauge HD PVR to do recordings of TV shows and movies. It's got lots of great features, it can wake your Mac from sleep to do a recording. In general it's a great piece of software. Plex is fantastic too. Getting recordings from EyeTV to Plex to watch on the Roku devices in my house didn't seem easy. Then I found this thread over at the Plex forums.

A huge thank you to everyone that worked on it. I tweaked it some for my setup...

UPDATE 23-Feb-2013
See this thread from Apple Forums for great comskip info.

-- 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 commander flatus 2/2013
-- remember that we're starting from the comskip post-processing script
-- i commented, documented a bit
-- this will directly export the H.264 that a Hauppauge HD PVR generates - very quickly
-- the resulting file is smaller than the iPad transcode and literally takes a minute if you generate recordings with this hardware
-- otherwise, this may be slower ymmv
-- Applescript is a dreadful language
-- Don't try to export directly to a network share unless you know what you're doing

-- as best i can tell etvcomskip doesnt do anything to my h.264 recordings
-- there is a donation version but from a cursory search it appears it wont work 
-- either. i mostly use this for movies and kids shows so it doesnt matter much for me

-- Some definitions below

-- variable thisTitle - raw title of show ie Seinfeldfrom eyeTV
-- variable ParsTitle - above with illegal filesystem characters removed
-- mcisrunning subroutine to check if markcommercials is running
-- parseout - subroutine to remove illegal filesystem characters
-- CheckMultiplePIDs - subroutine to check if multiple PIDs in one recording
-- variable rec - recordingID from EyeTV
-- variable theRec 
-- variable thisEpisode - text episode name ie The Puerto Rican Day Parade
-- variable EyeTvArchiveLocation location of recordings use colons instead of slashes
-- variable ExportLocation location where converted recordings go
-- variable TempLocation location for temporary files
-- variable fname location of eyetvp file for season and episode info
-- variable sid season number
-- variable eid episode number
-- variable tempEp episode title

global LogMsg

on RecordingDone(recordingID)
        set LogMsg to ""
        -- set up logfile
        -- 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
        -- Grab some basics from EyeTV. RecoringID, Show name, Episode name. It'll be used later.
        tell application "EyeTV"
                set rec to recordingID as integer
                set theRec to recording id rec
                set thisTitle to title of theRec
                set ParsTitle to my parseout(thisTitle)
                set thisEpisode to episode of theRec
        end tell
        -- Customize this script for yourself. The next three variables are locations on your system where we will read and export to
        -- Use complete paths, dont put network shares in here
        -- Set this value to the location where EyeTV records to
        set EyeTvArchiveLocation to "Macintosh HD:Users:ted:Documents:EyeTV Archive:" as string
        -- Set this location to where you want your exports to write to
        set ExportLocation to "Macintosh HD:Users:ted:Desktop:Plex:" as string
        -- Set this to a temporary location. A file "temp.plist" is written and then deleted from here
        set TempLocation to "Macintosh HD:Users:ted:" as string
        -- Now we're gonna go to the finder, find the show and grab the file out of the package that has the meta data. It'll be written to a temp file and we'll grab the season and episode # from it.
        tell application "Finder"
                -- Set the alias for the show we just got done recording
                -- This gives the script the filename of the eyetv recording in the filesystem
                if thisEpisode is "" then
                        set fpath to EyeTvArchiveLocation & ParsTitle & ".eyetv" as alias
                        set fpath to EyeTvArchiveLocation & ParsTitle & " - " & thisEpisode & ".eyetv" as alias
                end if
                -- The .eyetv file is a package. We're going to read it's contents and find the .eyetvp file. It'll be stored in the fname variable
                set eyetvp to do shell script "ls -1 " & quoted form of POSIX path of fpath & "/*.eyetvp" as string
                set eyetvp to every paragraph of eyetvp --   paragraph == line
                set fname to item 1 of eyetvp
        end tell
        -- Great! now grab Season number and Episode number out of this temp - eyetvp file and create the sedat variable. This will be used in the file export later.
        -- You can grab more meta data in this routine and also tweak the way the file name meta data is created.
        tell application "System Events"
                set fileRecord to (value of property list file fname)
                set sid to value of property list item "SEASONID" of property list item "epg info" of property list file fname
                set eid to value of property list item "EPISODENUM" of property list item "epg info" of property list file fname
        end tell
        tell application "Finder"
                -- set up directory for a show - ie Seinfeld directory to contain season directories and episode files
                -- if it doesn't exist, create it
                set fileLocation to ExportLocation & ParsTitle
                if not (exists folder fileLocation) then
                        make new folder at alias ExportLocation with properties {name:ParsTitle}
                end if
                -- set up directory for seasons and if it doesn't exist, create one
                set fileLocation to ExportLocation & ParsTitle & ":" & "Season " & sid
                set tempDir to ExportLocation & ParsTitle
                set tempFolder to "Season " & sid
                set tempSid to sid as string
                -- if season id is blank or zero just put shows in the main directory
                if (exists folder fileLocation) is false and tempSid is not "" and tempSid is not "0" then
                        make new folder at alias tempDir with properties {name:tempFolder}
                end if
        end tell
        -- Now, tell EyeTV to set the file name and location and export the file.
        -- TODO: I'd like to have an option to just rename the file in place here and/or export using Turbo.264 and/or export in HD720p format.
        tell application "EyeTV"
                set theDateStamp to (do shell script "date +%Y%m%d.%H%M%S")
                -- tempEp is the episode name
                set tempEp to thisEpisode as string
                if eid is not "" then
                        set tempEid to eid as integer
                        set tempEid to 0 as integer
                end if
                set tempSeason to sid as string
                -- if title, season, and episode numbers are not blank or zero
                -- file will look like Seinfeld:Season 10:Episode 3:Seinfeld S10E3.mp4
                -- mp4 is hardcoded because i'm just sucking out the H.264
                if tempEp is not "" and tempSeason is not "" and tempSeason is not "0" and tempEid is not "0" and tempEid is not "" then
                        set fileName to ExportLocation & ParsTitle & ":Season " & sid & ":" & ParsTitle & " " & "S" & sid & "E" & eid & ".mp4"
                else if tempSeason is not "" and tempSeason is not "0" then
                        --have season number, use Date AND NAME ie no episode number
                        set tempEpDate to (do shell script "date +%m%d%Y") as string
                        set fileName to ExportLocation & ParsTitle & ":Season " & sid & ":" & tempEp & "-" & tempEpDate & ".mp4"
                else if tempEp is not "" then
                        --at this point, should have no season number, no episode number, so just use name
                        set fileName to ExportLocation & ParsTitle & ":" & tempEp & ".mp4"
                        --No name, no season, no episode name just use  date for filename in directory of shows ie Seinfeld:03061999.mp4
                        set tempEpDate to (do shell script "date +%m%d%Y") as string
                        set fileName to ExportLocation & ParsTitle & ":" & tempEpDate & ".mp4"
                end if
                -- change this if you want, I just want the H.264 video
                -- if you're not capturing off of a Hauppauge HD PVR or similar this may make things slower, not faster!!!
                export from theRec to file fileName as "H.264"
        end tell
end RecordingDone

-- one more edit for plex export, only section below.
-- this subroutine isn't called from anywhere that i can tell-- if i remove it, something will certainly break because Applescript is a pain in the butt
on readFile(unixPath)
        set foo to (open for access (unixPath))
        set txt to (read foo for (get eof foo))
        close access foo
        return txtend readFile
-- this will not be called when triggered from EyeTV, but only when the script is run as a stand-alone script-- sets up a loop to run the export with all currently selected shows
on run
        tell application "EyeTV"
                set selectedRecordings to selection of programs window
                repeat with theRecording in selectedRecordings
                        --display dialog "theRecording ID " & (get unique ID of theRecording as integer)
                        set recordingID to unique ID of theRecording as integer
                        my RecordingDone(recordingID)
                end repeat
        end tellend run

on CheckMultiplePIDs(recordingID)
        --check if there are multiple Video PIDs in the file
        tell application "EyeTV"
                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 recording id recrdingIDInteger
                                set LogMsg to "RecordingDone found multiple PIDs for recording ID: " & recordingID & ", Channel " & (channel number of rec) & " - " & (title 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

-- read, write - self explanatory
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)
                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
                        close access file target_file
                end try
                return false
        end try
end write_to_file

-- runs comskip on shows
on launchComSkip(recID, pid)
        if pid = "" then
                set cmd to "'/Library/Application Support/ETVComskip/' --force --log " & recID & " &> /dev/null &"
                set cmd to "'/Library/Application Support/ETVComskip/' --force --log " & recID & " --pid=" & pid & " &> /dev/null &"
        end if
        do shell script cmd
end launchComSkip

--is markcommercials running?
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

--Subroutine to remove troublesome characters
to parseout(stringtoparse)
        set illegals to (ASCII character of 60) & (ASCII character of 62) & (ASCII character of 58) & (ASCII character of 34) & (ASCII character of 47) & (ASCII character of 92) & (ASCII character of 124)
        repeat with i from 1 to count (illegals)
                set testletter to (text i thru i of illegals)
                set the_offset to 1
                        set the_offset to offset of testletter in stringtoparse
                        if the_offset > 0 then
                                set stringtoparse to (text 1 thru (the_offset - 1) of stringtoparse) & "_" & (text (the_offset + 1) thru -1 of stringtoparse)
                                exit repeat
                        end if
                end repeat
        end repeat
        return stringtoparse
end parseout

No comments:

Post a Comment