#! /bin/bash # ***** WELCOME! Scroll further down to set the user settings. ***** #mythicalLibrarian by Adam Outler #email: adamoutler gmail.com #Software the way it should be: Free and Open Source #Please contact me with any bug reports #Tech Support: http://xbmc.org/forum/showthread.php?p=470402#post470402 #Intention: # This program is designed to be a user job in MythTV. It can be called by creating a user job. It must have access to your MythTV recordings # This file should be placed in /usr/local/bin # The user job can be called as follows: # /usr/local/bin/mythicalLibrarian "%DIR%/%FILE%" # #Usage: # mythicalLibrarian "Target File" "show name" "episode name" # eg. mythicalLibrarian "/home/myth/recordings/2308320472023429837.mpg" "South Park" "Here Comes the Neighborhood" # #Output-target # If an error occurs and the file cannot be moved, then no change will occur to the original file. If the Movedir # is full or not available, such as when running a NAS and the computer is disconnected from the network, the # AlternateMoveDir will be used. If both of these dirs fail, the show will be SymLinked in the FailSafeDir. # You may elect to run the user job at a later time when the issue has been resolved. Output dir and link type # will depend on user settings. The file name however, is preset to the most acceptable standard: # Show Title - SxxExx (Episode Title).ext # #Symlinking: # When Symlinking is enabled, mythicalLibrarian will follow its normal mode of operation. In MOVE mode, # mythicalLibrarian will create a symlink from the new file in the same name and location of the old file. In # LINK mode, mythicalLibrarian will not move the file, LINK mode creates a new symlink to the original file. # #Output-Files # mythicalLibrarian will create several files in it's working folder. This is a list of the files and their functions. # -created.tracking-keeps track of created comskip.txt and NFO files so they can be deleted in the future if their video file # is deleted. # -doover.sh is designed to keep track of failed jobs. It is designed to be executable. #Commented commands are # those which are determined to be questionable. This file can be made executable and ran after a problem is corrected # which caused the problem. Questionable commands are those which will require you to add a episode title and set the # mythicalLibrarian Database=Disabled setting. Questionable files do not have sufficient guide data. # -markupstart.txt and markupstop.txt are files which contain information from the last comskip generation. # Deletion will cause no adverse effects. # -output.log keeps track of operations and can be used to determine problems. # -shn.txt, sid.txt, and working.xml are used each time to determine the name and show id of the last show identified. # -The DailyReport folder is used to log the files which were moved that day. It can be used as a "program guide" of sorts # to keep track of what has been added to your library. # #Logging: # Log file will show information for troubleshooting. You can find the log file in the working folder # Log file default location: /home/mythtv/.mythicalLibrarian/output.log # #Database-external: # This program will make 3 calls to TheTvDb for every episode. The first one is to obtain the series ID and verify the show # name is correct. The seccond is to check if the internally managed database is up-to-date. The third call will only be # made if the internal database is not up-to-date. The third call will download a larger file which contains all information # about the show which is known on TheTvDb. # #Database-internal: # While mythicalLibrarian maintains and requires it's own external file/folder database in the working directory, there is # also support for integration with MythTV's internal database. MythTV Database is required for movies to be recognized and # handled by mythicalLibrarian. Also, in the event that the integrated fuzzy logic cannot make a determination of the # correct show name, mythicalLibrarian will pull the original air date from the MythTV database and attempt to make an # exact match to theTvDb.com supplied data. In addition, the type of program is extracted from the mythtv database and a # determination is made weather or not there is sufficient information available to identify the show based upon guide data # In order to make mythicalLibrarian work to it's full potential, all settings must be filled out correctly under the # database section of the user settings. Currently, the only guide data supported is schedulesdirect through mythtv. When # updating mythicalLibrarian it is best to delte all database folders to ensure proper data formatting. # #Dependencies: depends on "curl", "agrep", "libnotify-bin" and Mythtv Backend for database access. # install curl with "apt-get install curl" -curl downloads webpages and sends commands to XBMC # install agrep with "apt-get install agrep" -agrep provides fuzzy logic # optional: install libnotify-bin with "apt-get install libnotify-bin" -allows GNOME desktop notifications # #Ubuntu Notifications: # In order for mythicalLibrarian to send notifications to the GNOME desktop, it must have no-password sudo access. It uses # this access strictly to send complete, moving and failure status notifications. Because this program is launched by the # user mythtv under normal circumstances, mythtv must temporarily become your user name in order to send a notification to # your desktop. This requires the use of a separate script, and for mythtv to have a sudoers group with no password option. # Notifications are an optional feature and will only work on the MythTV backend computer. The librarian-notify-send script # should be located in /usr/local/bin. You can get this script here: # https://sourceforge.net/projects/mythicallibrari/files/mythicalLibrarianBeta/librarian-notify-send/download # #XBMC Notifications: # If options are enabled, mythicalLibrarian will send a http requests to a specified XBMC Server to display library updates, # to update the library and to clean out the library. In order for this to work XBMC you must ensure that the setting in # XBMC under System->Network->Services->Allow control of XBMC via HTTP and Allow programs on other systems to control XBMC # are enabled. #Show Name Translation # The user may elect to create a file in the mythicalLibrarian/ working folder which will then translate any recorded # show name into the desired show name. This is useful for adding a year to distinguish between a new series # and an older series and/or typos in your guide data. By default it should be called "showTranslations" and # it will be in your home/username/mythicalLibrarian folder. showTranslations is not needed by most users and the file # should only be created if it is needed. Under most circumstances, the integrated fuzzy logic will be # sufficient to translate the guide name to the TvDb name, however showTranslations is available to improve # accuracy to 100%. The format of showTranslations is as follows: #Filename: /home/mythtv/.mythicalLibrarian/showTranslations ############################################################## #My Guide Show Title = www.TheTvDb.com Show Title # #Battlestar Gallactica = Battlestar Gallactica (2003) # #The Office = The Office (US) # #Millionaire = Who Wants To Be A Millionaire # #Aqua teen Hungerforce = Aqua Teen Hunger Force # ############################################################## #######################USER SETTINGS########################## ###Stand-alone mode values### #SYMLINK has 3 modes. MOVE|LINK|Disabled: Default=MOVE #Create symlink in original dir from file after 'MOVE' | Do not move, just create a sym'LINK' | move the file, symlinking is 'Disabled' SYMLINK=MOVE #MoveDir is the folder which mythicalLibrarian will move the file. No trailing / is accepted eg. "~/videos" MoveDir="/home/mythtv/Episodes" #<------THIS VALUE MUST BE SET------- #AlternateMoveDir will act as a seccondary MoveDir if the primary MoveDir fails. No trailing / is accepted eg. "~/videos" AlternateMoveDir=/home/mythtv/Episodes #If TargetPathIsInputPath is Enabled, original dir will override MoveDir. Useful for multiple recording dirs. #TargetPathIsInputPath will separate generic shows from episodes and movies. Enabled|Disabled TargetPathIsInputPath=Enabled #Internet access Timeout in seconds: Default Timeout=50 (seconds) Timeout=50 #Update database time in secconds, Longer duration means faster processing time and less strain on TheTvDb. Default='84000' (1 day) UpdateDatabase=84000 #mythicalLibrarian working file dir: Default=~/mythicalLibrarian (home/username/mythicalLibraian) mythicalLibrarian=~/.mythicalLibrarian #FailSafe mode will enable symlinks to be formed in FailSafeDir if the move or symlink operation fails. Enabled|Disabled FailSafeMode=Enabled #FailSafeDir is used when the file cannot be moved to the MoveDir. FailSafe will not create folders. eg. /home/username FailSafeDir="/home/mythtv/FailSafe" #<------THIS VALUE MUST BE SET------- #DirTracking will check for and remove the folders created by mythicalLibrarian DirTracking=Enabled #the following line contains the API key from www.TheTvDb.Com. Default project code: 6DF511BB2A64E0E9 APIkey=0F3A338F0FCB29A2 #Language setting Language=en ###Database settings### #MythTV MYSQL access allows addition of movies, comskip data, and improves accuracy of episode recognition. #Database access Enabled|Disabled Database=Enabled #Database Type MythTV|MythTVPythonBindings Default=MythTVPythonBinding DatabaseType=MythTVPythonBindings #Guide data type: SchedulesDirect currently covers DataDirect, MC2XML and others. NoLookup will bypass tvdb scanning #Options: SchedulesDirect|NoLookup GuideDataType=SchedulesDirect #The IP address or name of the server for MythTV Database (used in python bindings only) DBHostName=localhost #MySQL User name: Default="mythtv" MySQLuser="mythtv" #MySQL Password: Default="mythtv" MySQLpass="mythtv" #<------THIS VALUE MUST BE SET------- #MythTV Backend server: Default=localhost MythTVBackendServer=localhost #The Database Pin for the MythTV Database (used in python bindings only) DBPin="0" #MySQL Myth Database: Default="mythconverg" #If utilizing mythconverg with Python Bindings, then it would be MySQLMythDb=PythonBindingsmythconverg MySQLMythDb=mythconverg #Primary Movie Dir. mythicalLibrarian will attempt to move to this dir first. No trailing / is accepted eg. "~/videos" PrimaryMovieDir="/home/mythtv/Movies" #<------THIS VALUE MUST BE SET------- #AlternateMoveDir will act as a Seccondary move dir if the primary moive dir fails AlternateMovieDir="/home/mythtv/Movies" #ShowStopper = Enabled prevents generic shows and unrecognized episodes from being processed ShowStopper="Enabled" #Primary Show Dir. mythicalLibrarian will attempt to move to this dir first. No trailing / is accepted eg. "~/videos" PrimaryShowDir="/home/mythtv/Showings" #<------THIS VALUE MUST BE SET------- #AlternateMoveDir will act as a Seccondary move dir if the primary moive dir fails AlternateShowDir="/home/mythtv/Showings" #CommercialMarkup will generate comskip files for recordings when they are moved. Enabled|Disabled CommercialMarkup=Enabled #CommercialMarkupCleanup will execute a maintenance routine which will remove comskip files if they are not needed CommercialMarkupCleanup=Enabled ###Reporting/Communications### #Enables debug mode. This is a verbose mode of logging which should be used for troubleshooting. Enabled|Disabled DEBUGMODE=Enabled #DailyReport provides a local log of shows added to your library per day. Enabled|Disabled DailyReport=Enabled #Notify tells mythicalLibrarian to send a notification to GNOME Desktop upon completion. Enabled|Disabled Notify=Enabled #If notifications are enabled, NotifyUserName should be the same as the user logged into the GNOME Session. (your username) NotifyUserName="adam" #<------THIS VALUE MUST BE SET------- #Send a notification to XBMC to Update library upon Successful move job Enabled|Disabled XBMCUpdate=Enabled #Send a notification to XBMC to cleanup the library upon Successful move job Enabled|Disabled XBMCClean=Enabled #Send Notifications to XBMC UI when library is updated Enabled|Disabled XBMCNotify=Enabled #Ip Address and port for XBMC Notifications Eg.XBMCIPs=( "192.168.1.110:8080" "192.168.1.111:8080" "XBOX:8080" ) XBMCIPs=( "192.168.1.110:8080" "XBOX:8080" ) #<------THIS VALUE MUST BE SET------- #maxItems controls the number of items in the RSS. RSS Can be activated by creating a folder in /var/www/mythical-rss. maxItems=8 #########################USER SETTINGS########################## ########################## USER JOBS############################ #The RunJob function is a place where you can put your custom script to be run at the end of execution #Though it may be at the top, this is actually the end of the program. RunJob () { case $jobtype in #Successful Completion of mythicalLibrarian LinkModeSuccessful|MoveModeSuccessful) echo "SUCCESSFUL COMPLETION TYPE: $jobtype" #Insert Custom User Job here # exit 0 ;; #Information was not obtainable TvDbIsIncomplete|GenericShow) echo "INSUFFICIENT INFORMATION WAS SUPPLIED:$jobtype" #Insert Custom User Job here # exit 0 ;; #File system error occoured PermissionError0Length|InvalidFileNameSupplied|PermissionErrorWhileMoving|FailSafeModeComplete|LinkModeFailed) echo "FILE SYSTEM ERROR:$jobtype" #Insert Custom User Job here # exit 1 ;; #Generic error occoured GenericUnspecifiedError) echo "UNKNOWN ERROR OCCOURED:$jobtype" #Insert Custom User Job here # exit 2 ;; #User elected not to process jobs which can not be properly categorized NameCouldNotBeAssigned) echo "NAME COULD NOT BE ASSIGNED BASED UPON DATA SUPPLIED" #Insert Custom User Job here # exit 3 ;; #User elected to use a title/category ignore file titleIgnore|categoricIgnore) echo "Show Was ignored based on $jobtype" #Insert Custom User Job Here # exit 0 ;; esac #Custom exit point may be set anywhere in program by typing RunJob on any new line #Insert Custom User Job here # exit 4 } ########################## USER JOBS############################ ################################################################ ############Adept personel only beyond this point############### ################################################################ ####USER JOBS#### # mythicalLibrarian --update (mythicalSetup) will merge user jobs into mythicalLibrarian automagically. # Put your desired commands into one of the following files. You may need to create the folder # /etc/mythicalLibrarian/JobSucessful # /etc/mythicalLibrarian/JobInformationNotComplete # /etc/mythicalLibrarian/JobGenericError # /etc/mythicalLibrarian/JobFilesystemError # /etc/mythicalLibrarian/JobInsufficientData # /etc/mythicalLibrarian/JobIgnoreList # /etc/mythicalLibrarian/JobUnspecified # After running mythicalSetup, the user job will be encorperated into the mythicalLibrarian script and # Executed when the job is run. ###EXAMPLE JOB ### # /etc/mythicalLibrarian/JobSucessful: # #Transcode your file using the mythicalLibrarian variables #ffmpeg -i S:"$MoveDir/$ShowFileName.$OriginalExt" -target ntsc-svcds:"$MoveDir/$ShowFileName.mp4" # #remove the mythicalLibrarian symlink #rm "$InputPath" # #make a new symlink #ln -s "$MoveDir/$ShowFileName.mp4" "$InputPath" # #Set the new file extension #OriginalExt=mp4 # #Create tracking entry for the file #performLoggingForMoveMode # ####Move the .txt(comskip) and .nfo(Information) files if needed. # enable the XBMC communications #XBMCUpdate=Enabled #XBMCClean=Enabled #XBMCNotify=Enabled # #Tell mythicalLibrarian to do XBMC communications #XBMCAutomate #The following is a list of variables which can be used as a part of user jobs at the end of mythicalLibrarian #Suggested examples are: #1.string together multiple versions of mythicalLibrarian configured for different languages. Set a different #Language for each, then on failure, call the next job. #2.custom name replacement of certain programming #3.custom file moving of certain programming #4.set custom folders based upon recorded channel #5.set custom user jobs based upon who ran the file #6.make a "new movies" "old movies" folder. #The limits are endless. #####ALL RECORDINGS#### #$MoveDir/$ShowFileName.$OriginalExt = location of moved file. #$ShowName = Processed Title #$InputTitle = actual database title #$MoveDir = the folder to which the file was moved ie. "/home/mythtv/videos/Episode" #$ShowFileName = the name of the show moved, not including extension eg. "simpsons S01E02 (foo)" or "MovieTitle(year)" #$OriginalExt = original file extension eg "mpg" #$NewShowName = Successfully resolved show name #$ChanID = ChannelID #$ProgramID= Zap2it listing #$ShowStartTime = begin recording time #$ShowCategory = category like children or sports #$mythicalLibrarianProgramIDCheck = "SH" for SHow or sports - "MV" for MoVie - "EP" for EPisode #$Plot = Plot #$Stars = Stars #$FileBaseName = name of the file to be moved without ext #$XMLTVGrabber = your guide data type #$ProgramIDType= Generic episode with no data, Movie, or Series With Episode Data #$Zap2itSeriesID= Zap2it ID with SH, MV or EP stripped #$MyUserName = name of user running mythicalLibrarian #$SafeShowName = title of show after showTranslations formatted for filesystem use ####EPISODES AND GENERIC SHOWS#### #$OriginalAirDate = original air date Generic programming will be the first episode ever, for episodes it will be the first aired date #$EpisodeSubtitle = Subtitle or EPisode Name #####EPISODES#### #$Exx = Episode Number or "Movie" in case of a movie #$Sxx = Season number or blank in case of movie #$SeriesID = TheTVDB series ID #$TvDbTime = current tvdb time #$LastUpdated = last updated time (for Episodes only others wil be blank) # = tvdb order numbering ####MOVIES#### #$MovieAirDate = the original year the movie aired #########BEGIN FUNCTIONS HERE######### TraditionalNamingConventions () { #Format Episodes showname=show name Sxx=season number Exx=episode number EpisodeSubtitle=episode name if [ "$Exx" != "" ] && [ "$Exx" != "E" ]; then ShowFileName=`echo "$NewShowName $Sxx$Exx ($EpisodeSubtitle)"` #Format Movies elif [ "$mythicalLibrarianProgramIDCheck" = "MV" ]; then Exx="Movie" MoveDir="$PrimaryMovieDir" if [ "$MovieAirDate" != "" ]; then ShowFileName="$NewShowName ($MovieAirDate)" else ShowFileName="$NewShowName" fi #Format generic Shows else Exx="Generic" MoveDir="$PrimaryShowDir" ShowFileName=`echo "$ShowName S0E0 ($EpisodeSubtitle Recorded $datehour on $ChanID)"` RequiresNFO=1 test "$mythicalLibrarianProgramIDCheck" = "EP" && RequiresDoover=1 fi } CategoricNamingConventions () { #Method1 - use airdate for season if [ "${OriginalAirDate:0:4}" != "0000" ] && [ "${OriginalAirDate:0:4}" != "" ] && [ "$UseMethod2" != "1" ] ; then EventYear="${OriginalAirDate:0:4}" Sxx=$EventYear EventMonthDay=`echo "${OriginalAirDate:5:5}"|tr -d "-"|sed 's/0*//'` Exx=$EventMonthDay test "$NewShowName" = "" && NewShowName=$ShowName #Check validity of Method1 else testedmethod1=0 fi if [ "$EventMonthDay" != "" ] && [ "$EventYear" -gt "1900" ] && [ "$EventMonthDay" -gt "0" ]; then testedmethod1=1 else testedmethod1=0 fi #Method2 if [ "$testedmethod1" != "1" ]; then test "${ShowStartTime:0:4}" != 0000 && test "${ShowStartTime:0:4}" != "" && EventYear="${ShowStartTime:0:4}" && EventMonthDay=`echo "${ShowStartTime:5:5}"|tr -d "-"|sed 's/0*//'` Exx=$EventMonthDay Sxx=$EventYear #Check validity of Method2 fi test "$EventYear" -gt "1900" && test "$EventMonthDay" -gt "0" && ShowFileName="$NewShowName S$EventYear""E$EventMonthDay ($InputSubtitle Recorded $datehour)" RequiresNFO=1 HasSxxExx=1 } ######DAILY REPORT##### #This function reports all shows processed based on date dailyreport () { if [ $DailyReport = Enabled ]; then test ! -d "$mythicalLibrarian/DailyReport" && mkdir "$mythicalLibrarian/DailyReport" reportfilename=`date +%Y-%m-%d` reporttime=`date +%T` echo "$reporttime - $ShowFileName">>"$mythicalLibrarian/DailyReport/$reportfilename" fi return 0 } #####CHECK PERMISSIONS##### #CheckPermissions by writing a small file then deleting it, checking along the way. #CheckPermissions takes file size, free space on dir, and the dir, then it performs #tests. the result will be $TMoveDirWritable as a 1 or a 0 for writable or not. #$1=filesize $2=freespace $3=folder to check checkPermissions () { #set Test variable to 0. It will be a 1 if everything passes. TMoveDirWritable=0 if [ "$2" != "" ]; then if [ "$1" != "" ]; then if [ -d "$3" ]; then if [ $1 -lt $2 ]; then echo "Testing write permission on $3">"$3/arbitraryfile.ext" if [ -f "$3/arbitraryfile.ext" ] ; then if [ -s "$3/arbitraryfile.ext" ]; then rm -f "$3/arbitraryfile.ext" test ! -f "$3/arbitraryfile.ext" && TMoveDirWritable=1 || TMoveDirWritable=0 else TMoveDirWritable=0 echo "CREATED $3/arbitraryfile.ext BUT COULD NOT WRITE DATA INTO THE FILE" |tee -a "$mythicalLibrarian/output.log" fi else echo "$MyUserName TRIED TO WRITE TO $3 --FAILED" |tee -a "$mythicalLibrarian/output.log" test ! -r "$3" && echo "QUICK FIX: sudo chmod a+r \"$3\"" |tee -a "$mythicalLibrarian/output.log" test ! -w "$3" && echo "QUICK FIX: sudo chmod a+w \"$3\"" |tee -a "$mythicalLibrarian/output.log" echo "QUICK FIX: sudo chown $MyUserName \"$3\"" |tee -a "$mythicalLibrarian/output.log" fi elif [ -z "$2" -o $1 -ge $2 ]; then TMoveDirWritable=0 echo "INSUFFICIENT FREE SPACE ON $3" |tee -a "$mythicalLibrarian/output.log" echo "QUICK FIX: Remove unnecessary files" |tee -a "$mythicalLibrarian/output.log" fi else echo "FOLDER DOES NOT EXIST: $3" |tee -a "$mythicalLibrarian/output.log" echo "QUICK FIX: mkdir \"$3\"" |tee -a "$mythicalLibrarian/output.log" fi else echo "COULD NOT READ FILESIZE ON $InputPath" |tee -a "$mythicalLibrarian/output.log" echo "QUICK FIX: chmod -R 775 \"$InputPath\"" |tee -a "$mythicalLibrarian/output.log" fi else echo "COULD NOT READ FREE SPACE on \"$3\"" |tee -a "$mythicalLibrarian/output.log" echo "QUICK FIX: mkdir \"$3\" ; chmod -R 775 \"$3\"" |tee -a "$mythicalLibrarian/output.log" fi return 0 } #####COMSKIP FILES##### #Function GenComSkip creates a comskip.txt file for use with the show upon moving, created from data from library GenComSkip () { mythicalLibrarianCounter=1 #Set up comskip file test -f "$mythicalLibrarian/markupframes.txt" && rm -f "$mythicalLibrarian/markupframes.txt" echo "FILE PROCESSING COMPLETE">"$mythicalLibrarian"/markupframes.txt echo "------------------------">>"$mythicalLibrarian"/markupframes.txt while read line do mythicalLibrarianCounter=`expr $mythicalLibrarianCounter + 1`; StartData=`sed -n "$mythicalLibrarianCounter"p "$mythicalLibrarian/markupstart.txt"` StopData=`sed -n "$mythicalLibrarianCounter"p "$mythicalLibrarian/markupstop.txt"` if [ ! -z "$StopData" ]; then echo "$StartData $StopData">>"$mythicalLibrarian"/markupframes.txt CommercialMarkup="Created" echo "COMMERCIAL DATA START:$StartData STOP:$StopData" fi done <"$mythicalLibrarian/markupstop.txt" return 0 } #####XBMC COMMUNICATIONS##### #This function Automates communication with XBMC XBMCAutomate () { #Send notification to XBMC, Update Library, Clean Library if [ "$XBMCNotify" = "Enabled" -o "$XBMCUpdate" = "Enabled" -o "$XBMCClean" = "Enabled" ]; then for XBMCIP in ${XBMCIPs[@]} do echo "SENDING REQUESTED COMMANDS TO:$XBMCIP" test "$XBMCNotify" = "Enabled" && curl -L -s -m3 --connect-timeout 5 "http://"$XBMCIP"/xbmcCmds/xbmcHttp?command=ExecBuiltIn(Notification(mythical%20Librarian%2Cadding%20show%2​0$tvdbshowname%20to%20library))" > /dev/null 2>&1 test "$XBMCUpdate" = "Enabled" && curl -L -s -m3 --connect-timeout 5 "http://"$XBMCIP"/xbmcCmds/xbmcHttp?command=ExecBuiltIn(UpdateLibrary(video))" > /dev/null 2>&1 test "$XBMCClean" = "Enabled" && curl -L -s -m3 --connect-timeout 5 "http://"$XBMCIP"/xbmcCmds/xbmcHttp?command=ExecBuiltIn(CleanLibrary(video))" > /dev/null 2>&1 done fi return 0 } #####GENERATE RSS ENTRY##### #This function generates an RSS feed for use on the web server. This can be used in /home/xbmc/.xbmc/userdata/RssFeeds.xml #replace the feeds.feedburner.com link with http://[youripaddress]/mythical-rss/rss.xml #Big thanks to barney_1! generaterss() { #user settings: rssDir="/var/www/mythical-rss" maxItems=8 #maximum number of items to read into the feed #script settings OLDrssFile="rss.xml" TEMPrssFile="rss.temp" #HTML line break code for nice formatting lineBreak="<br />" #test if rssFile directory is writeable if [ ! -w "$rssDir" ]; then echo -e "RSS generation failed:\nDirectory not writeable ($rssDir)" return 5 fi #test if rssFile is writeable if [ -e "$rssDir/$OLDrssFile" ] && [ ! -w "$rssDir/$OLDrssFile" ]; then echo -e "RSS generation failed:\nFile exists but is not writeable: $rssDir/$OLDrssFile" return 6 fi #Setup the rss file echo -e '' > $rssDir/$TEMPrssFile echo -e '' >> $rssDir/$TEMPrssFile echo -e '' >> $rssDir/$TEMPrssFile echo -e '\tmythicalLibrarian' >> $rssDir/$TEMPrssFile echo -e '\thttp://xbmc.org' >> $rssDir/$TEMPrssFile echo -e '\tmythicalLibrary Daily Report Information' >> $rssDir/$TEMPrssFile #write current recording information to first item. echo -e "\t\t">>$rssDir/$TEMPrssFile echo -e "\t\t\t$NewShowName">>$rssDir/$TEMPrssFile if [ "$mythicalLibrarianProgramIDCheck" = "EP" ]; then echo -e "\t\t\thttp://www.thetvdb.com/?tab=series&id=$SeriesID">>$rssDir/$TEMPrssFile elif [ "$mythicalLibrarianProgramIDCheck" = "MV" ]; then echo -e "\t\t\thttp://www.thetvdb.com/?tab=series&id=$ShowName">>$rssDir/$TEMPrssFile else tvdotcomshowname=`echo $ShowName|sed s/" "/"%20"/g` echo -e "\t\t\thttp://www.tv.com/search.php?type=11&stype=all&tag=search%3Bfrontdoor&qs=$tvdotcomshowname ">>$rssDir/$TEMPrssFile fi which ifconfig >/dev/null && myip=`ifconfig | grep 'inet addr' -m1 | cut -d: -f2 | awk '{ print $1}'` rssEpisodeSubtitle=`echo $EpisodeSubtitle| sed s/"&"/"&"/g` rssNewShowName=`echo $NewShowName| sed s/"&"/"&"/g` rssPlot=`echo $Plot| sed s/"&"/"&"/g` mythicalGUID=`echo "$MyUserName@$myip""$MoveDir/$ShowFileName.$OriginalExt"| sed s/"("/"%28"/g| sed s/")"/"%29"/g|sed s/"\ "/"%20"/g` echo -e "\t\t\tsftp://$mythicalGUID">>$rssDir/$TEMPrssFile echo -e "\t\t\t"$(date -R -d "$ShowStartTime")"">>$rssDir/$TEMPrssFile echo -e "\t\t\t">>$rssDir/$TEMPrssFile echo -e "\t\t\t\tEpisode Title: $rssepn$lineBreak">>$rssDir/$TEMPrssFile echo -e "\t\t\t\tProgram: $rssNewShowName$lineBreak">>$rssDir/$TEMPrssFile echo -e "\t\t\t\tSeason: $Sxx$lineBreak">>$rssDir/$TEMPrssFile echo -e "\t\t\t\tEpisode #: $Exx$lineBreak$lineBreak">>$rssDir/$TEMPrssFile echo -e "\t\t\t\t$Plot">>$rssDir/$TEMPrssFile echo -e "\t\t\t">>$rssDir/$TEMPrssFile echo -e "\t\t">>$rssDir/$TEMPrssFile #If there is an old RSS file if [ -e "$rssDir/$OLDrssFile" ]; then #test for number of tags using grep RssItemCount=$(grep -c "" "$rssDir/$OLDrssFile") #if $maxItems is greater than this number if [ $maxItems -gt $RssItemCount ]; then #set a variable to track this number + 1 for the new entry itemLimit=$(($RssItemCount+1)) else #set tracking variable to $maxItems itemLimit=$maxItems fi #get the line number for the first tag firstLine=$(grep -n -m 1 "" "$rssDir/$OLDrssFile" | cut -d ":" -f 1) #get the line number for our last tag lastLine=$(grep -n -m $(($itemLimit-1)) "" "$rssDir/$OLDrssFile" | tail -n1 | cut -d ":" -f 1) #set IFS to use line break as a delineator OLDIFS=$IFS IFS=' ' #Read in the old RSS file declare -a old_rss_data=( $(cat "$rssDir/$OLDrssFile") ) arrayLen=${#old_rss_data[@]} #iterate through the array for index in $(seq $((firstLine-1)) $((lastLine-1))) do echo "${old_rss_data[$index]}" >> $rssDir/$TEMPrssFile done #copy line from old to new #if copied line is #increment counter #if counter is great than tracking variable #break fi #close the file. echo -e '\t' >> $rssDir/$TEMPrssFile echo -e '' >> $rssDir/$TEMPrssFile #move fully formed temp file on top of the old file mv "$rssDir/$TEMPrssFile" "$rssDir/$OLDrssFile" echo "RSS ENTRY SUCCESSFULLY CREATED: $rssDir/$OLDrssFile" IFS=$OLDIFS return 0 } #####MOVE MODE LOGGING##### #This function provides logging for move mode performLoggingForMoveMode () { #Create undo and doover file if not present test ! -f "$mythicalLibrarian/undo.sh" && echo "rm -f \"$mythicalLibrarian/undo.sh\"">>"$mythicalLibrarian/undo.sh" && chmod 666 "$mythicalLibrarian/undo.sh" test ! -f "$mythicalLibrarian/doover.sh" && echo "rm -f \"$mythicalLibrarian/doover.sh\"">>"$mythicalLibrarian/doover.sh" && chmod 666 "$mythicalLibrarian/doover.sh" test "$SYMLINK" != "Disabled" && echo "test -L \"$InputPath\" && rm -f \"$InputPath\" && echo removed \"$InputPath\"">>"$mythicalLibrarian/undo.sh" test "$SYMLINK" != "Disabled" && echo "test -f \"$MoveDir/$ShowFileName.$OriginalExt\" && mv \"$MoveDir/$ShowFileName.$OriginalExt\" \"$InputPath\" && echo moved \"$MoveDir/$ShowFileName.$OriginalExt\" to \"$InputPath\"">>"$mythicalLibrarian/undo.sh" if [ "$SYMLINK" = "MOVE" ]; then test "$RequiresDoover" = "1" && echo "test -f \"$MoveDir/$ShowFileName.$OriginalExt\" && test -L \"$InputPath\" && rm -f \"$InputPath\" && echo Moving \"$InputPath\" to original location">>"$mythicalLibrarian/doover.sh" test "$RequiresDoover" = "1" && echo "test -f \"$MoveDir/$ShowFileName.$OriginalExt\" && mv \"$MoveDir/$ShowFileName.$OriginalExt\" '$InputPath'">>"$mythicalLibrarian/doover.sh" test "$RequiresDoover" = "1" && echo "mythicalLibrarian \"$InputPath\" \"$InputTitle\" \"$InputSubtitle\"" >>"$mythicalLibrarian/doover.sh" fi } #####LINK MODE LOGGING##### #This function performs logging for link mode performLoggingForLinkMode () { #Create undo and doover file if not present test ! -f "$mythicalLibrarian/undo.sh" && echo "rm -f \"$mythicalLibrarian/undo.sh\"" >> "$mythicalLibrarian/undo.sh" && chmod 666 "$mythicalLibrarian/undo.sh" test ! -f "$mythicalLibrarian/doover.sh" && echo "rm -f \"$mythicalLibrarian/doover.sh\"">>"$mythicalLibrarian/doover.sh" && chmod 666 "$mythicalLibrarian/doover.sh" test "$RequiresDoover" = "1" && echo "test -L \"$MoveDir/$ShowFileName.$OriginalExt\" && rm -f \"$MoveDir/$ShowFileName.$OriginalExt\"">>"$mythicalLibrarian/doover.sh" test "$RequiresDoover" = "1" && echo "mythicalLibrarian \"$InputPath\" \"$InputTitle\" \"$InputSubtitle\"">>"$mythicalLibrarian/doover.sh" echo "test -L \"$MoveDir/$ShowFileName.$OriginalExt\" && rm -f \"$MoveDir/$ShowFileName.$OriginalExt\"">>"$mythicalLibrarian/undo.sh" echo "'$MoveDir/$ShowFileName.$OriginalExt'" "'$InputPath'">>"$mythicalLibrarian"/created.tracking } writeJobToDooverQue (){ test "$InputPath" != "" && echo "mythicalLibrarian '$1' '$2' '$3'">>$mythicalLibrarian/doover.sh } doFailSafeMode(){ echo "FAILSAFE FLAG WAS SET CHECK PERMISSIONS AND FOLDERS">>"$mythicalLibrarian"/output.log echo "FAILSAFE FLAG WAS SET" if [ $FailSafeMode = "Enabled" ]; then echo "PERMISSION ERROR OR DRIVE FULL">>"$mythicalLibrarian"/output.log echo "ATTEMPTING SYMLINK TO FAILSAFE DIR: $FailSafeDir">>"$mythicalLibrarian"/output.log echo "ATTEPMTING SYMLINK TO FAILSAFE DIR" ln -s "$InputPath" "$FailSafeDir/$ShowFileName.$OriginalExt" test -f "$FailSafeDir/$ShowFileName.$OriginalExt";echo "FAILSAFE MODE COMPLETE: SYMLINK CREATED">>"$mythicalLibrarian"/output.log test ! -f "$FailSafeDir/$ShowFileName.$OriginalExt"; echo "FAILSAFE MODE FAILURE CHECK PERMISSIONS AND FREE SPACE IN $FailSafeDir">>"$mythicalLibrarian"/output.log fi test $Notify = Enabled && sudo -u "$NotifyUserName" /usr/local/bin/librarian-notify-send "mythicalLibrarian FAILSAFE" "FAILSAFE mode active See "$mythicalLibrarian"/output.log for more information" error } #####MYTHTV DATABASE##### #This function gathers information from the mythtv database for use in the program GetMythTVDatabase () { if [ "$PythonBindings" != "True" ]; then #Obtain MythTV Database Information echo "Accessing MythTV DataBase:" #get Title test "$InputTitle" = "" && InputTitle=`mysql -u$MySQLuser -p$MySQLpass -e "use '$MySQLMythDb' ; select title from recorded where basename like '$InputFileBasename'; "|sed s/"title"/""/g|sed -n "2p"` #get Subtitle test "$InputSubtitle" = "" && InputSubtitle=`mysql -u$MySQLuser -p$MySQLpass -e "use '$MySQLMythDb' ; select subtitle from recorded where basename like '$InputFileBasename' ; "|sed s/"subtitle"/""/g|sed -n "2p"` #get chanid for recordings to identify program table ChanID=`mysql -u$MySQLuser -p$MySQLpass -e "use '$MySQLMythDb' ; select chanid from recorded where basename like '$InputFileBasename';"|sed s/"\/"/""/g|sed -n 2p|sed s/"chanid"/""/g|sed s/" "/""/g` #get ProgramID from recorded to identify program ProgramID=`mysql -u$MySQLuser -p$MySQLpass -e "use '$MySQLMythDb' ; select programid from recorded where basename like '$InputFileBasename' ; " |sed s/"\/"/""/g|sed -n "2p"|sed s/"programid"/""/g` #Get zap2it series id from basename to identify program Zap2itSeriesID=`mysql -u$MySQLuser -p$MySQLpass -e "use '$MySQLMythDb' ; select seriesid from recorded where basename like '$InputFileBasename' ; " |sed s/"\/"/""/g|sed -n "2p"|sed s/"seriesid"/""/g` #Get Plot from basename to identify program Plot=`mysql -u$MySQLuser -p$MySQLpass -e "use '$MySQLMythDb' ; select description from recorded where basename like '$InputFileBasename' ; " |sed s/"\/"/""/g|sed -n "2p"|sed s/"description"/""/g` #Get rating from basename to identify program Stars=`mysql -u$MySQLuser -p$MySQLpass -e "use '$MySQLMythDb' ; select stars from recorded where basename like '$InputFileBasename' ; " |sed s/"\/"/""/g|sed -n "2p"|sed s/"Stars"/""/g` #get show start time to identify program ----future development ShowStartTime=`mysql -u$MySQLuser -p$MySQLpass -e "use '$MySQLMythDb' ; select starttime from recorded where basename like '$InputFileBasename' ; " |sed s/"\/"/""/g|sed -n "2p"|sed s/"starttime"/""/g` #get category from recorded to identify program table -----future development ShowCategory=`mysql -u$MySQLuser -p$MySQLpass -e "use '$MySQLMythDb' ; select category from recorded where basename like '$InputFileBasename' ; " |sed s/"\/"/""/g|sed -n "2p"|sed s/"category"/""/g` #get original air date for tv shows OriginalAirDate=`mysql -u$MySQLuser -p$MySQLpass -e "use '$MySQLMythDb' ; select originalairdate from recorded where basename like '$InputFileBasename' ; "|sed s/"\/"/""/g|sed -n "2p"|sed s/"originalairdate"/""/g` test "$OriginalAirDate" = "0000-00-00" && OriginalAirDate="$null" #get DataType XMLTVGrabber=`mysql -u$MySQLuser -p$MySQLpass -e "use '$MySQLMythDb' ; select xmltvgrabber from videosource ; "|sed s/"xmltvgrabber"/""/g|sed s/"\/"/""/g|sed -n "2p"|sed s/" "/""/g` #get year for movies MovieAirDate=`mysql -u$MySQLuser -p$MySQLpass -e "use '$MySQLMythDb' ; select airdate from recordedprogram where programid like '$ProgramID' and chanid like '$ChanID' ; "|sed s/"\/"/""/g|sed s/"airdate"/""/g|sed -n "2p"|sed s/" "/""/g` #Blank year if it is invalid if [ ! -z "$MovieAirDate" ] && [ $MovieAirDate -lt 1900 ]; then MovieAirDate=$null fi #####COMSKIP DATA##### #Set up counter, remove old markup data and generate new markup file from markupstart and stop if [ "$CommercialMarkup" = "Enabled" ]; then #Remove old and generate a comskip Start list echo "">$mythicalLibrarian/markupstart.txt mysql -u$MySQLuser -p$MySQLpass -e "use '$MySQLMythDb' ; select mark from recordedmarkup where starttime like '$ShowStartTime' and chanid like '$ChanID' and type like "4" ; " |sed s/"mark"/""/g|sed s/" "/""/g>>$mythicalLibrarian/markupstart.txt #Remove old and generate comskip Stop list echo "">$mythicalLibrarian/markupstop.txt mysql -u$MySQLuser -p$MySQLpass -e "use '$MySQLMythDb' ; select mark from recordedmarkup where starttime like '$ShowStartTime' and chanid like '$ChanID' and type like "5" ; " |sed s/"mark"/""/g|sed s/" "/""/g>>$mythicalLibrarian/markupstop.txt GenComSkip fi return 0 fi } #####UTILIZE PYTHON BINDINGS TO GET MYTHTV DB##### Requires dependency GetMythTvPythonBindings() { echo "Attemting to pull database information on $InputPath" #make a named pipe for database output test ! -p "$mythicalLibrarian/mythicalDbOut" && mkfifo "$mythicalLibrarian/mythicalDbOut" #run the python bindings and output to named pipe /usr/local/bin/MythDataGrabber --filename="$InputFileBasename" --DBPin="$DBPin" --DBHostName="$DBHostName" --DBName="$MySQLMythDb" --DBUserName="$MySQLuser" --DBPassword="$MySQLpass"> "$mythicalLibrarian/mythicalDbOut" & pythonExitStatus=$? test "$pythonExitStatus" != "0" && echo "DATABASE ACCESS ERROR: COULD NOT OBTAIN INFORMATION \n Check DBInfo in mythicalSetup, verify file is mythtv file" #read values from named pipe, remove quotes and declare $Variable=$Value while read var equals value do value=`echo $value|tr -d \"` test "$equals" = "=" && declare $var="$value" echo $var$equals$value done < "$mythicalLibrarian/mythicalDbOut" > /dev/null 2>&1 if [ "$CommercialMarkup" = "Enabled" ]; then #Output commercial data to initial files printf "%s\n" "${startdata[@]}" >$mythicalLibrarian/markupstart.txt printf "%s\n" "${stopdata[@]}" >$mythicalLibrarian/markupstop.txt #Combine commercial data into a single comskip file and remove the initial files GenComSkip fi #Import mythtv values into mythicalLibrarian values, don't clobber title, subtitle. test "$InputTitle" = "" && InputTitle=$title test "$InputSubtitle" = "" && InputSubtitle=$subtitle; #redefine database var names into mythicalLibrarian var names MovieAirDate=$airdate OriginalAirDate=$originalairdate ShowCategory=$category Stars=$stars Plot=$description Zap2itSeriesID=$seriesid ProgramID=$programid ChanID=$chanid ShowStartTime=$starttime #cleanup, remove the fifo named pipe test -p "$mythicalLibrarian/mythicalDbOut" && rm -f "$mythicalLibrarian/mythicalDbOut" } #####PROCESS DATABASE INFORMATION##### #Function ProcessSchedulesDirect processes Zap2it/SchedulesDirect/Tribune data for use in the program ProcessSchedulesDirect () { #Check for database permissions test "$ChanID" = "" && echo "%%%NO DATABASE INFORMATION. CHECK LOGIN/PASS OR FILE %%%%%">>$mythicalLibrarian/output.log #disqualify invalid movie airdates test ! -z "$MovieAirDate" && test $MovieAirDate -lt 1900 && MovieAirDate=$null test "$OriginalAirDate" = "None" && $OriginalAirDate="" test "$OriginalAirDate" = "none" && $OriginalAirDate="" #Get rating from Stars rating=`printf "%0.f" $Stars` test $rating != "" && let rating=$rating*2 test $rating = "" && rating=1 #Create MV/EP/SH Identification Type from ProgramID mythicalLibrarianProgramIDCheck=${ProgramID:0:2} #Extrapolate data from Programid test "$mythicalLibrarianProgramIDCheck" = "SH" && ProgramIDType="Generic Episode With No Data" test "$mythicalLibrarianProgramIDCheck" = "MV" && ProgramIDType="Movie" test "$mythicalLibrarianProgramIDCheck" = "EP" && ProgramIDType="Series With Episode Data" test "$mythicalLibrarianProgramIDCheck" = "SP" && ProgramIDType="Sports Programming" && mythicalLibrarianProgramIDCheck=SH #account for .0123's in EITonly data type ProgramID=`echo $ProgramID|cut -f1 -d"."` #Check if database contains enough information to put into doover que GoForDoover=0 test "${x:0:2}" = "EP" && echo woot test "$EpisodeSubtitle" != "" && GoForDoover=1 #Get barebones zap2it series id. Zap2itSeriesID=`echo $ProgramID| tr -d MVSHEP | sed 's/0*//' | sed 's/.\{4\}$//' ` #strip needless chars from date datehour=`echo "$ShowStartTime"|tr ":" "."|tr " " "@"` #get 4 digit year seasonyear=`echo "${ShowStartTime:0:4}"` #predefined naming conventions if [ "$ShowCategory" = "Sports event" -o "$ShowCategory" = "News" -o "$ShowCategory" = "Newsmagazine" ]; then NamingConvention=$ShowCategory fi #If news, bypass Categoric naming convention 1 test NamingConvention="News" && UseMethod2=1 return 0 } #####PROCESS DATABASE INFORMATION##### ####NoLookup is an alternate mode where TheTvDb is not used for lookups ProcessNoLookup () { #Check for database permissions test "$ChanID" = "" && echo "%%%NO DATABASE INFORMATION. CHECK LOGIN/PASS OR FILE %%%%%">>$mythicalLibrarian/output.log #disqualify invalid movie airdates test ! -z "$MovieAirDate" && test $MovieAirDate -lt 1900 && MovieAirDate=$null #Get rating from Stars rating=`printf "%0.f" $Stars` test $rating != "" && let rating=$rating*2 test $rating = "" && rating=1 #Create MV/EP/SH Identification Type from ProgramID mythicalLibrarianProgramIDCheck=${ProgramID:0:2} #Spoof show as episode to avoid programid test "$mythicalLibrarianProgramIDCheck" = "EP" && ProgramIDType="Generic Episode With No Data" && mythicalLibrarianProgramIDCheck="SH" #Extrapolate data from Programid test "$mythicalLibrarianProgramIDCheck" = "SH" && ProgramIDType="Generic Episode With No Data" test "$mythicalLibrarianProgramIDCheck" = "MV" && ProgramIDType="Movie" test "$mythicalLibrarianProgramIDCheck" = "SP" && ProgramIDType="Sports Programming" && mythicalLibrarianProgramIDCheck=SH #account for .0123's in EITonly data type ProgramID=`echo $ProgramID|cut -f1 -d"."` datehour=`echo "$ShowStartTime"|tr ":" "."|tr " " "@"` seasonyear=`echo "${ShowStartTime:0:4}"` if [ "$ShowCategory" = "Sports event" -o "$ShowCategory" = "News" -o "$ShowCategory" = "Newsmagazine" ]; then NamingConvention=$ShowCategory fi test NamingConvention="News" && UseMethod2=1 return 0 } #####REMOVE ENTRIES FROM LIBRARY##### #remove mythtv recording's pictures and database entries. Thanks to barney_1. DeleteRelevantDatabaseFilesAndPictures () { #Make sure we got input arguments and file is valid if [ ! -e "$InputPath" ]; then #Remove recording entry from mysql database echo "REMOVING - $FileBaseName - THUMBNAILS - DATABASE ENTRIES"|tee -a "$mythicalLibrarian"/output.log mysql -u$MySQLuser -p$MySQLpass -e "use '$MySQLMythDb' ; delete from recorded where basename like '$FileBaseName'; " #Remove thumbnails rm -f "$originaldirname/$FileBaseName".* fi return 0 } #####USE AbsoluteEpisodeNumber TO SET SXX AND EXX##### setSxxAndExxFromAbsoluteEpisodeNumber() { #if line match is obtained, then gather new episode name, Sxx and Exx EpisodeSubtitle=`sed -n $AbsoluteEpisodeNumber'p' "$mythicalLibrarian"/"$NewShowName"/"$NewShowName".actualEname.txt` #gather series and episode names from files created earlier. Exx=`sed -n $AbsoluteEpisodeNumber'p' "$mythicalLibrarian"/"$NewShowName"/"$NewShowName".E.txt` Sxx=`sed -n $AbsoluteEpisodeNumber'p' "$mythicalLibrarian"/"$NewShowName"/"$NewShowName".S.txt` test $Sxx != "" && SeasonNumber=$Sxx #Single digit episode and show names are not allowed Ex and Sx replaced with Exx Sxx test $Exx -lt 10 && Exx="E0$Exx" || Exx="E$Exx" test $Sxx -lt 10 && Sxx="S0$Sxx" || Sxx="S$Sxx" echo "EPISODE:$EpisodeSubtitle EPISODE NUMBER:$AbsoluteEpisodeNumber $Sxx$Exx WITH CONFIDENCE: $EpisodeConfidenceRating" } determineIfDatabaseIsUpToDate(){ #Get current server time test -f "$mythicalLibrarian/$NewShowName/current.time" && rm -f "$mythicalLibrarian/$NewShowName/current.time" curl -L -s -m"$Timeout" "http://www.thetvdb.com/api/Updates.php?type=none">"$mythicalLibrarian/$NewShowName/current.time" #Get the time from the file test -f "$mythicalLibrarian/$NewShowName/current.time" && CurrentTime=`cat "$mythicalLibrarian/$NewShowName/current.time"|grep '