Home Featured Renaming Tatort video files with Hazel

Renaming Tatort video files with Hazel

0
Renaming Tatort video files with Hazel
Tatort

I’m not a fan of linear TV watching. Therefore, I try to automatically download TV content that I want to watch either as Podcasts to my smartphone or as video files to my computer. The famous German TV show ‘Tatort’ is an example of the later category. How to automatically download ‘Tatort’ media files to your computer will be a topic for a separate post. This blog post however is about automatically renaming ‘Tatort’ media files with the help of ‘Hazel‘ and ‘AppleScript’.

The challenge

When downloading the latest ‘Tatort’ episode they normally only have the episode title in the file name, such as ‘Tatort-Taxi nach Leipzig.mp4. Other ‘Tatort’ files that I came across either had the episode ID such as ‘1000.mp4’ or the the season/episode number such as ‘S2016E32.mp4’ in the file name.

However, as a ‘KODI‘ and ‘Plex‘ user I would need structured file names that contain the relevant episode information in order that the two media systems are able to identify the correct ‘Tatort’ episodes. Furthermore, I personally want to have the investigator name in the file name as well. Therefore, my preferred naming scheme would be:

  • Scheme: Tatort – S<season:yyyy>E<episode:[e]e> – <id:iiii> – <title:text> – <investigator:text>.mp4
  • Example: Tatort – S2016E32 – 1000 – Taxi nach Leipzig – Lindholm.mp4

So far, I had to open a website, looking up the missing data and manually update the file name of the downloaded MP4 file. As this was too much (manual) work every week I decided to write an AppleScript for ‘Hazel‘ that would rename the MP4 files for me.

The solution

My new workflow now is:

  • I check if the file name of my ‘Tatort’ media file is formatted according to one of the following three options:
    1) episode title, e.g. ‘Taxi nach Leipzip.mp4’
    2) episode ID, e.g. ‘1000.mp4’
    3) season/episode numbering, e.g. ‘S2016E32.mp4’
    If the file name does not match any of the the above mentioned options I start watching/scrolling the beginning of the ‘Tatort’ episode. Luckily with macOS’ built-in ‘QuickView’ this can be done with little effort. I just have to hit the space bar when the media file is selected in ‘macOS Finder’.
  • At this point my ‘Hazel Tatort Workflow’ kicks in. The workflow reads the file name of the MP4 file and hands it over to the the AppleScript. The AppleScript downloads a XML file from the internet and looks up the relevant episode information. This information is then handed back to the ‘Hazel’ workflow which saves the final file name of the the MP4 file und uploads the file to the correct folder on my ‘NAS’.

The following image gallery shows how to to setup such a workflow in Hazel.

[masterslider id=”2″]

 

Additional comments for each individual step:

  • Step 1: Create a new ‘Hazel’ workflow for the folder where your new ‘Tatort’ media files are coming in. The matching condition can be set to files of the kind ‘Movie’. Then add the first rule action of the type ‘Run AppleScript’ to the workflow. Copy & paste the whole code that is listed below to this rule action as embedded code.
  • Step 2: Define the import and export values of the rule action ‘Run AppleScript’. The only import value required by the AppleScript is the file name. The export values can be defined by the user. In total there are nine export values to choose from. Please read the comments in the code for further details. It’s important that all export values with a ‘true’ value in the code show up in exactly the same sequence in Hazel’s ‘Script export’ box as in the code. If you have no idea what the instructions in this step mean, then just copy the same setup as shown in the image of ‘Step 2’.
  • Step 3: Create your preferred naming scheme for your ‘Tatort’ media files. Note that the available elements may depend on your settings in ‘Step 2’.
  • Step 4: Define the subfolder(s) where your ‘Tatort’ media files shall be copied. This step is optional.
  • Step 5: Move your ‘Tatort’ media files to your preferred storage device (internal or external hard disk, NAS, etc.). This step is optional.

Note that there can be a significant lag between the moment you copy the ‘Tatort’ media file to the watched folder and the moment Hazel is actually renaming the file. On the one hand this is due to the fact that ‘Hazel’ itself has some built-in delays until a ‘Hazel’ rule is executed. On the other hand it is also because of the poor performance of ‘AppleScript’ execution on ‘macOS’.

---- Script info ------------------------------------
--    - Version: 9.2
--    - Last updated: 06.08.2018
--    - Creator: Andreas Hess
--    - URL: https://blogx.ch/blog/technology/renaming-tatort-files-with-hazel-1/
--    - Copyright: Andreas Hess, May 2018
--    - License: GNU GPLv3

---- Description -----------------------------------
-- This script was developed as a 'Hazel Rule Action'. The script either accepts the episode title (e.g. "Taxi nach Leipzig"), the episode ID (e.g. "1000") or 
-- the season/episode number (e.g. "S2016E32") as input parameter from Hazel. It then downloads a XML file with all "Tatort" information, searches the 
-- input parameter in the XML file and returns the episode parameters the user has defined. 
-- Note 1: TV Stations have used some episode titles more than one time (e.g. "Taxi nach Leipzig"). As Hazel does not allow the AppleScript to interact with the 
-- user (e.g. with the help of a pop-up window), it is not possible for the script to know which of the several possible episodes has to be returned. Therefore
-- the scripts stops after it found the first match. This problem arises only if you use title as search term, but not if you use episode ID or season/episode number.
-- You can change the behavior from returning the 'first result found' to the 'last result found' by setting the parameter 'forceLastResult' to true. Also see below.
-- Note 2: The XML file is hosted in my public folder of my Dropbox account. The file will regularly be updated with the latest episode information. The data within 
-- the XML file is sorted "newest to oldest". To find the information of an old episode it will take considerably longer processing time than for an episode that was 
-- recently aired.
--
-- The following parameters can be defined as true/false values:
--    - forceEnglishSeriesName: returns either "Tatort" or "Crime of the Scene" as series name
--    - forceCreateReleaseDateObject: forces the code to create a AppleScript date object with the release date of the episode. Only needed if you have some special date calculation needs and you want to extend this script.
--    - forceTwoDigitEpisodeNumber: forces the code to return a two-digit episode number (e.g. "02" instead of "2"). Only relevant for output, not for input/search.
--    - forceFourDigitIDNumber: forces the code to return a four-digit episode ID (e.g. "0865" instead of "865"). Only relevant for output, not for input/search.
--    - forceGermanTransliteratedUmlauts: forces the code to replace German umlauts (Ä,Ö,Ü,ä,ö,ü) to transliterated umlauts (Ae,Oe,Ue,ae,oe,ue). Only relevant for output, not for input/search.
--    - forceReplaceGermanDoubleS: forces the code to replace German double S ('ß') with normal double S ('ss'). Only relevant for output, not for input/search.
--    - forceLastResult: forces the code to continue the search for the last occurence of the episode title in the XML file. In general, requires longer processing time!
--
-- The following true/false parameters indicate the return values of the script
--    - returnSeriesNameValue: returns the series name, also see parameter 'forceEnglishSeriesName'
--    - returnDateValue: returns the release date of the episode formatted as DD.MM.YYYY, also see parameter 'forceCreateReleaseDateObject'
--    - returnSeasonValue: returns the season value of the episode (e.g. "2015")
--    - returnEpisodeValue: returns the episdoe value, also see parameter 'forceTwoDigitEpisodeNumber'
--    - returnIDValue: returns the consecutive episode ID (e.g. "865") from the beginning of 'Tatort' in 1970, also see parameter 'forceFourDigitIDNumber'
--    - returnTitleValue: returns the episode title (e.g. "Taxi nach Leipzig")
--    - returnInvestigatorValue: returns the name of the investigator (e.g. "Schimanski")
--    - returnTvStationValue: returns the name of the releasing TV station (e.g. "NDR")
--    - returnSeasonEpisodeValue: returns the season/episode number (e.g. "S2015E15"), also see parameter 'forceTwoDigitEpisodeNumber'
--
-- Search parameter -----------------
-- The following three types of search terms can be used as input value:
--    - Episode title: small/capital letters and special characters do not influence the search, e.g. the search term "kaelter ALS Der tod" or "Cote dAzur" will match the correct episodes "Kälter als der Tod" respectively "Côte d'Azur"
--    - Episode ID: use integer numbers, e.g. "1", "65", "865", "1025" or special characters like "168a" as ID search terms. Do not add leading zeros, e.g. "0865" or "0168a"
--    - Season/Episode: use syntax 'SyyyyE[x]x', e.g. "S2015E15". Do not add leading zeros for episode number, e.g. use "S2015E5" instead of "S2015E05"
--
---- Notes ----------------------
-- You can use this script either in Hazel or with Apple's Script Editor for testing purposes. The only change that has to be done is the setup of the input variable.
--    - for Hazel: activate this line -> set theCurrentFileName to item 1 of inputAttributes
--    - for Script Editor: activate this line -> set theCurrentFileName to "Taxi nach Leipzig"
-- Activating means removing the two dashes "--" in front of the code. Note: only one of these code lines should be active, the other line should be commented out by two dashes "--"


-- Parameters for processing ----------------------
set forceEnglishSeriesName to false as boolean
set forceCreateReleaseDateObject to false as boolean
set forceTwoDigitEpisodeNumber to true as boolean
set forceFourDigitIDNumber to true as boolean
set forceGermanTransliteratedUmlauts to false as boolean
set forceReplaceGermanDoubleS to true as boolean
set forceLastResult to false as boolean


-- Parameters for return values ------------------
set returnSeriesNameValue to false as boolean
set returnDateValue to false as boolean
set returnSeasonValue to true as boolean
set returnEpisodeValue to false as boolean
set returnIDValue to true as boolean
set returnTitleValue to true as boolean
set returnInvestigatorValue to true as boolean
set returnTvStationValue to false as boolean
set returnSeasonEpisodeValue to true as boolean

---- Download XML file with Tatort information and store it on the harddisk. Helpful resource were:
--    - https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/WorkwithXML.html
--    - https://discussions.apple.com/thread/3386494?start=15&tstart=0
set myXMLCmd to " /usr/bin/curl -O -J -L 'Cache-Control: no-cache' 'https://www.dropbox.com/s/16zfe4sf5i6xpxc/tatort.xml?dl=0' > /tmp/tatort.xml"
do shell script myXMLCmd

-- receive the filename from Hazel or set the file name manually for testing purposes (one of the following two code lines must be deactivated)
set theCurrentFileName to item 1 of inputAttributes -- code line required for execution within Hazel
-- set theCurrentFileName to "Tatort - Taxi nach Leipzig" as text -- code line required for exectuion within Apple Script Editor for testing purposes --> either enter ID (e.g. "1000"), title (e.g. "Taxi nach Leipzig") or series/episode identifcation (such as SyyyEx, e.g. "S2017E5")

-- the file names of Tatort media files automatically downloaded by Synology Download Manager can contain the text prefix "Tatort" with a random string such as "-", " -", "- " or " - ". This text needs to be removed.
if theCurrentFileName starts with "Tatort - " then
	set theCurrentFileName to characters 10 thru (length of theCurrentFileName) of theCurrentFileName as text
else if theCurrentFileName starts with "Tatort- " then
	set theCurrentFileName to characters 9 thru (length of theCurrentFileName) of theCurrentFileName as text
else if theCurrentFileName starts with "Tatort -" then
	set theCurrentFileName to characters 9 thru (length of theCurrentFileName) of theCurrentFileName as text
else if theCurrentFileName starts with "Tatort-" then
	set theCurrentFileName to characters 8 thru (length of theCurrentFileName) of theCurrentFileName as text
end if

-- AppleScript can ignore the difference e.g. between "a" and "ä", but not between "ä" and "ae". File names containing e.g. "ae" instead of "ä" need to be changed in order to find the correct title in the XML file
set theCurrentFileNameUmlauts to theCurrentFileName as text

if theCurrentFileName contains "ae" or theCurrentFileName contains "oe" or theCurrentFileName contains "ue" then
	considering case
		set myItemsToBeReplaced to {"ae", "oe", "ue", "Ae", "Oe", "Ue"}
		set myItemsToReplace to {"ä", "ö", "ü", "Ä", "Ö", "Ü"}
		set prevTxtItemDelimiters to AppleScript's text item delimiters
		repeat with i from 1 to length of myItemsToBeReplaced
			set AppleScript's text item delimiters to item i of myItemsToBeReplaced
			set the item_list to every text item of theCurrentFileNameUmlauts
			set AppleScript's text item delimiters to item i of myItemsToReplace
			set theCurrentFileNameUmlauts to the item_list as text
		end repeat
		set AppleScript's text item delimiters to prevTxtItemDelimiters
	end considering
end if

-- set the result variables
set myValueList to {}
set myResultArray to {}

-- XML processing routine
tell application "System Events"
	tell XML file "/tmp/tatort.xml"
		tell XML element "tatort"
			tell XML element "episodes"
				set myEpisodes to every XML element whose name = "episode"
				repeat with i from 1 to length of myEpisodes
					set myEpisode to item i of myEpisodes
					tell myEpisode
						-- start retrieving and formating the 3 search terms
						set myID to value of XML attribute "id" as text -- search term 1
						-- display dialog myID
						set myDateTxt to value of XML attribute "date"
						set mySeasonInt to (text 7 thru 10 of myDateTxt) as integer
						set myEpisodeInt to value of XML attribute "no" as integer
						set mySeasonEpisodeTxt to "S" & mySeasonInt & "E" & myEpisodeInt as text -- search term 3
						set myTitleTxt to value of XML attribute "title" as text -- search term 2
						
						-- check if the current XML item matches with the file name provided by Hazel. If yes, put together the return values as list object.
						ignoring case, diacriticals, hyphens and punctuation
							if (myID = theCurrentFileName or myTitleTxt = theCurrentFileName or myTitleTxt = theCurrentFileNameUmlauts or mySeasonEpisodeTxt = theCurrentFileName) then
								-- start formating the series name (DE or EN)
								if (forceEnglishSeriesName) then
									set mySeriesNameTxt to "Scene of the Crime" as text -- translated series name according to TheTVDB.com
								else
									set mySeriesNameTxt to "Tatort" as text
								end if
								
								-- start formating an AppleScript date object for the release date of the episode
								if (forceCreateReleaseDateObject) then
									set myDateObj to the current date
									set the day of myDateObj to (text 1 thru 2 of myDateTxt)
									set the month of myDateObj to (text 4 thru 5 of myDateTxt)
									set the year of myDateObj to mySeasonInt
									set the hours of myDateObj to "20"
									set the minutes of myDateObj to "15"
									set the seconds of myDateObj to "0"
									-- add code here for formating/calculating the date/time according to your needs and assign the formated/calculated date/time to the variable 'myDateTxt' as text
								end if
								
								-- start of formating the episode number
								if (forceTwoDigitEpisodeNumber) then
									set myEpisodeTxt to text -2 thru -1 of ("00" & myEpisodeInt) as text
								else
									set myEpisodeTxt to myEpisodeInt as text
								end if
								
								-- put the season/episode string togehter
								set mySeasonEpisodeTxt to "S" & mySeasonInt & "E" & myEpisodeTxt as text
								
								-- start of replacing German umlauts with transliterated umlauts
								if (forceGermanTransliteratedUmlauts) then
									considering case and diacriticals
										set myItemsToBeReplaced to {"ä", "ö", "ü", "Ä", "Ö", "Ü"}
										set myItemsToReplace to {"ae", "oe", "ue", "Ae", "Oe", "Ue"}
										set prevTxtItemDelimiters to text item delimiters of AppleScript
										repeat with i from 1 to length of myItemsToBeReplaced
											set AppleScript's text item delimiters to item i of myItemsToBeReplaced
											set the item_list to every text item of myTitleTxt
											set AppleScript's text item delimiters to item i of myItemsToReplace
											set myTitleTxt to the item_list as string
										end repeat
										set text item delimiters of AppleScript to prevTxtItemDelimiters
									end considering
								end if
								
								-- start of replacing German double S ('ß') with normal double S ('ss').
								if (forceReplaceGermanDoubleS) then
									set myItemsToBeReplaced to {"ß"}
									set myItemsToReplace to {"ss"}
									repeat with i from 1 to length of myItemsToBeReplaced
										set prevTxtItemDelimiters to text item delimiters of AppleScript
										set AppleScript's text item delimiters to item i of myItemsToBeReplaced
										set the item_list to every text item of myTitleTxt
										set AppleScript's text item delimiters to item i of myItemsToReplace
										set myTitleTxt to the item_list as string
										set text item delimiters of AppleScript to prevTxtItemDelimiters
									end repeat
								end if
								
								-- start of formating the ID number. Some episodes have a character in the ID, e.g. '168a'. these need to handled separately.
								set myLastChar to (get last character of myID)
								if "1234567890" does not contain myLastChar then
									set myIDTemp to characters 1 thru ((length of myID) - 1) of myID as text
									set myIDInt to myIDTemp as integer
								else
									set myIDInt to myID as integer
									set myLastChar to ""
								end if
								-- add leading zero for ID numbers below 1000. Note that the ID number will become 5 digit if the ID contains a character, eg. '168a' becomes '0168a'.
								if (forceFourDigitIDNumber) then
									set myIDTxt to text -4 thru -1 of ("0000" & myIDInt) & myLastChar as text
								else
									set myIDTxt to myIDInt & myLastChar as text
								end if
								
								-- start of assigning Investigator and TV Station
								set myInvestigatorTxt to value of XML attribute "inv" as text
								set myTvStationTxt to value of XML attribute "tvs" as text
								
								-- start putting the values of the episode into an AppleScript list object
								if (returnSeriesNameValue) then set myValueList to {mySeriesNameTxt}
								if (returnDateValue) then set myValueList to myValueList & {myDateTxt}
								if (returnSeasonValue) then set myValueList to myValueList & {mySeasonInt}
								if (returnEpisodeValue) then set myValueList to myValueList & {myEpisodeTxt}
								if (returnIDValue) then set myValueList to myValueList & {myIDTxt}
								if (returnTitleValue) then set myValueList to myValueList & {myTitleTxt}
								if (returnInvestigatorValue) then set myValueList to myValueList & {myInvestigatorTxt}
								if (returnTvStationValue) then set myValueList to myValueList & {myTvStationTxt}
								if (returnSeasonEpisodeValue) then set myValueList to myValueList & {mySeasonEpisodeTxt}
								
								set myResultArray's end to myValueList
								set myValueList to {}
								
								if (forceLastResult is false) then
									exit repeat
								end if
							end if
						end ignoring
					end tell
				end repeat
			end tell
		end tell
	end tell
end tell

-- clean up --> delete XML file
do shell script "rm /tmp/tatort.xml"

-- throw an error if nothing has been found or return the calculated values back to Hazel
if (length of myResultArray is 0) then
	error "No match found!"
else
	return {hazelOutputAttributes:last item of myResultArray}
end if

If you want you can also download a standalone script file that can be executed within ‘Apple Script Editor’. Read the comments within the script (especially the ‘Note’ section) to learn about the differences of the ‘Hazel script’ and the ‘Standalone script’.

[ddownload id=”704″ text=”Tatort AppleScript v9.2 (%filesize%)”]

LEAVE A REPLY

Please enter your comment!
Please enter your name here