Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/nov13/FixTranscription.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/nov13/FixTranscription.groovy	(revision 3016)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/nov13/FixTranscription.groovy	(revision 3017)
@@ -3,6 +3,7 @@
 import javax.xml.stream.*
 
 import org.txm.importer.PersonalNamespaceContext
+import org.txm.utils.FileUtils
 import org.txm.xml.IdentityHook
 import org.txm.xml.*
 
@@ -19,9 +20,34 @@
 	LocalNamesHookActivator activator;
 	IdentityHook hook;
 	
-	public FixTranscription(File xmlfile) {
+	def primarySpeakerIdRegex
+	String primarySpeakerId
+	
+	Boolean debug
+	
+	String otherNonPrimaryLocutor = "other"
+	
+	public FixTranscription(File xmlfile, String primarySpeakerIdPrefix, String otherNonPrimaryLocutor, Boolean debug) {
 		super(xmlfile)
+		this.debug = debug
 		
+		this.otherNonPrimaryLocutor = otherNonPrimaryLocutor
+		if (primarySpeakerIdPrefix != null && primarySpeakerIdPrefix.length() > 0) {
+			String id = FileUtils.stripExtension(xmlfile)
+			
+			this.primarySpeakerIdRegex = /$primarySpeakerIdPrefix.*/
+			
+			def rez = (id =~ primarySpeakerIdRegex).findAll()
+			def rez2 = (id =~ /$primarySpeakerIdPrefix/).findAll()
+			if (rez2.size() != 1) {
+				if (debug) println "WARNING: found the ${rez2.size()} matches of primary speaker prefix in the '$id' file name"
+				this.primarySpeakerIdRegex = null
+			} else {
+				primarySpeakerId = rez[0]
+				//if (debug) println "Detected primary speaker: $primarySpeakerId"
+			}
+		}
+		
 		activator = new LocalNamesHookActivator<>(hook, ["w", "Turn", "Sync"]);
 		
 		hook = new IdentityHook("word_hook", activator, this) {
@@ -103,7 +129,12 @@
 								def tmpInfos = new LinkedHashMap()
 								for (String attr : turnInfos.keySet()) tmpInfos[attr] = turnInfos[attr]
 								tmpInfos["orig-speaker"] = turnInfos["speaker"]
-								tmpInfos["speaker"] = "other"
+								
+								if (primarySpeakerIdRegex == null || turnInfos["speaker"] ==~ primarySpeakerIdRegex) {
+									tmpInfos["speaker"] = "other"
+								} else {
+									tmpInfos["speaker"] = primarySpeakerId
+								}
 								tmpInfos["startTime"] = currentTime
 								writer.writeStartElement("Turn")
 								for (String attr : tmpInfos.keySet()) {
@@ -130,7 +161,7 @@
 								writer.writeEndElement() // event
 								word = "" // don't write the word
 							}
-														
+							
 							if (word.length() > 0) {
 								
 								writer.writeStartElement("w") // start the initial word
@@ -140,7 +171,7 @@
 								writer.writeCharacters(word)
 								writer.writeEndElement() // w
 							}
-						
+							
 							if (shouldCloseOtherTurn) {
 								shouldCloseOtherTurn = false;
 								//close the current 'other' Turn and restart the actual Turn
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/nov13/FixTranscriptionsMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/nov13/FixTranscriptionsMacro.groovy	(revision 3016)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/nov13/FixTranscriptionsMacro.groovy	(revision 3017)
@@ -6,14 +6,23 @@
 import org.txm.utils.logger.*
 
 @Field @Option(name="trsFile", usage="A single vocapia XML file", widget="FileOpen", required=false, def="")
-		File trsFile;
+		File trsFile
 
 @Field @Option(name="trsDirectory", usage="A Vocapia XML files directory to process", widget="Folder", required=false, def="")
-		File trsDirectory;
+		File trsDirectory
 
 @Field @Option(name="resultDirectory", usage="The result directory", widget="Folder", required=false, def="")
-		File resultDirectory;
+		File resultDirectory
+		
+@Field @Option(name="primarySpeakerIdPrefix", usage="speaker ID of the primary speaker", widget="String", required=false, def="")
+		String primarySpeakerIdPrefix
 
+		@Field @Option(name="otherNonPrimaryLocutor", usage="other non primary id of the other turns", widget="String", required=false, def="")
+		String otherNonPrimaryLocutor
+		
+@Field @Option(name="debug", usage="speaker ID of the primary speaker", widget="Boolean", required=false, def="false")
+		Boolean debug
+
 if (!ParametersDialog.open(this)) return;
 
 if (resultDirectory.equals(trsDirectory) || (trsFile != null && trsFile.getParentFile().equals(resultDirectory))) {
@@ -44,7 +53,8 @@
 ConsoleProgressBar cpb = new ConsoleProgressBar(trsFiles.size())
 for (File file : trsFiles) {
 	cpb.tick()
-	FixTranscription fixer = new FixTranscription(file)
+	
+	FixTranscription fixer = new FixTranscription(file, primarySpeakerIdPrefix, otherNonPrimaryLocutor, debug)
 	String name = FileUtils.stripExtension(file)
 	File outFile = new File(resultDirectory, name+".trs")
 	
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/RenameSpeaker.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/RenameSpeaker.groovy	(revision 0)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/RenameSpeaker.groovy	(revision 3017)
@@ -0,0 +1,151 @@
+package org.txm.macro.transcription
+
+import org.txm.scripts.importer.*;
+import org.txm.utils.*;
+import org.txm.metadatas.*;
+
+import java.io.File;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.xml.parsers.*;
+import javax.xml.xpath.*;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+/** 
+ * Renames speakers given an id or name regex
+ **/
+public class ChangeSpeaker {
+	File outfile, transcriptionfile
+	
+	/** The doc. */
+	Document doc
+	
+	def idRegex, nameRegex
+	String newId, newName
+	
+	/**
+	 * Instantiates a new change speaker.
+	 *
+	 * @param transcriptionfile the transcriptionfile
+	 * @param outfile the outfile
+	 * @param id the id
+	 * @param newid the newid
+	 */
+	public ChangeSpeaker(File transcriptionfile, File outfile, String idRegexString, String nameRegexString, String newId, String newName) {
+		
+		this.transcriptionfile = transcriptionfile
+		this.outfile = outfile;
+		
+		if (idRegexString != null && idRegexString.length() > 0) {
+			this.idRegex = /$idRegexString/
+		}
+		if (nameRegexString != null && nameRegexString.length() > 0) {
+			this.nameRegex = /$nameRegexString/
+		}
+		this.newId = newId
+		this.newName = newName
+	}
+	
+	/**
+	 * Save.
+	 *
+	 * @return true, if successful
+	 */
+	public boolean process() {
+		try {
+			DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
+			domFactory.setNamespaceAware(true); // never forget this!
+			domFactory.setXIncludeAware(true);
+			DocumentBuilder builder = domFactory.newDocumentBuilder();
+			doc = builder.parse(transcriptionfile);
+			
+			
+			def expr2 = XPathFactory.newInstance().newXPath().compile("//Speaker");
+			def nodes2 = expr2.evaluate(doc, XPathConstants.NODESET);
+			
+			// fix speaker declarations
+			def replacedIds = [] // list of IDs replaced, the list is used later to update the Turn locutors ids
+			
+			for (def node : nodes2) {
+				if (node == null) continue;
+				Element elem = (Element)node;
+				
+				String id = elem.getAttribute("id")
+				String name = elem.getAttribute("name")
+				
+				if (idRegex != null && id =~ idRegex) { // patch Speaker@id
+					if (newId != null) {
+						elem.setAttribute("id", newId);
+						replacedIds << id
+					}
+					if (newName != null) {
+						elem.setAttribute("name", newName);
+					}
+				}
+				
+				if (nameRegex != null && id =~ nameRegex) { // patch Speaker@name
+					if (newName != null) {
+						elem.setAttribute("name", newName);
+					}
+				}
+			}
+			
+			
+			def expr = XPathFactory.newInstance().newXPath().compile("//Turn");
+			def nodes = expr.evaluate(doc, XPathConstants.NODESET);
+			
+			// fix speaker turns
+			
+			for (def node : nodes) {
+				if (node == null) continue;
+				
+				Element elem = (Element)node;
+				String id = elem.getAttribute("speaker");
+				
+				if (replacedIds.contains(id)) {
+					elem.setAttribute("speaker", newId);
+				}
+			}
+			
+			// Création de la source DOM
+			Source source = new DOMSource(doc);
+			
+			// Création du fichier de sortie
+			Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outfile), "UTF-8"));
+			Result resultat = new StreamResult(writer);
+			
+			// Configuration du transformer
+			TransformerFactory fabrique = new net.sf.saxon.TransformerFactoryImpl();
+			Transformer transformer = fabrique.newTransformer();
+			transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+			transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+			
+			// Transformation
+			transformer.transform(source, resultat);
+			writer.close();
+			return true;
+		} catch (Exception e) {
+			org.txm.utils.logger.Log.printStackTrace(e);
+			return false;
+		}
+	}
+	
+	/**
+	 * The main method.
+	 *
+	 * @param args the arguments
+	 */
+	public static void main(String[] args) {
+		String homedir = System.getProperty("user.home")
+		File trs1 = new File(homedir, "xml/concattrs/int18_1.trs")
+		File trs2 = new File(homedir, "xml/concattrs/int18_1-renamed.trs")
+		
+		new RenameSpeaker(trs1, trs2, "spk2", null, "spk4", null).process();
+		
+	}
+}
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/RenameSpeakerMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/RenameSpeakerMacro.groovy	(revision 0)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/RenameSpeakerMacro.groovy	(revision 3017)
@@ -0,0 +1,31 @@
+package org.txm.macro.transcription
+
+import java.nio.charset.Charset
+
+import java.time.LocalTime
+import java.time.format.DateTimeFormatter
+import org.txm.utils.*
+import org.txm.utils.logger.*
+
+@Field @Option(name="trsFile", usage="Dossier qui contient les fichiers TRS", widget="FileOpen", required=true, def="")
+File trsFile;
+
+@Field @Option(name="outputTrsFile", usage="Dossier qui contient les fichiers TRS", widget="FileSave", required=true, def="")
+File outputTrsFile;
+
+@Field @Option(name="idRegex", usage="Colonne de jointure de transcription", widget="String", required=true, def="")
+def idRegex
+
+@Field @Option(name="nameRegex", usage="Colonne de jointure de transcription", widget="String", required=true, def="")
+def nameRegex
+
+@Field @Option(name="idRegex", usage="Colonne de jointure de transcription", widget="String", required=true, def="")
+def newID
+
+@Field @Option(name="nameRegex", usage="Colonne de jointure de transcription", widget="String", required=true, def="")
+def newName
+
+
+def cs = new RenameSpeaker(trsFile, outputTrsFile, idRegex, nameRegex, newID, newName);
+
+return cs.process();
\ No newline at end of file
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/RenameSpeakerFromDirectoryMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/RenameSpeakerFromDirectoryMacro.groovy	(revision 0)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/RenameSpeakerFromDirectoryMacro.groovy	(revision 3017)
@@ -0,0 +1,50 @@
+package org.txm.macro.transcription
+
+import java.nio.charset.Charset
+
+import java.time.LocalTime
+import java.time.format.DateTimeFormatter
+import org.txm.utils.*
+import org.txm.utils.logger.*
+
+@Field @Option(name="trsDirectory", usage="Dossier qui contient les fichiers TRS", widget="Folder", required=true, def="")
+File trsDirectory;
+
+@Field @Option(name="outputTrsDirectory", usage="Dossier résultat qui contient les fichiers TRS", widget="Folder", required=true, def="")
+File outputTrsDirectory;
+
+@Field @Option(name="idRegex", usage="Colonne de jointure de transcription", widget="String", required=true, def="")
+def idRegex
+
+@Field @Option(name="nameRegex", usage="Colonne de jointure de transcription", widget="String", required=true, def="")
+def nameRegex
+
+@Field @Option(name="newID", usage="Colonne de jointure de transcription", widget="String", required=true, def="")
+def newID
+
+@Field @Option(name="newName", usage="Colonne de jointure de transcription", widget="String", required=true, def="")
+def newName
+
+def files = trsDirectory.listFiles()
+if (files == null) {
+	println "Error: no files in $trsDirectory"
+	return false
+}
+
+outputTrsDirectory.mkdirs()
+if (!outputTrsDirectory.exists()) {
+	println "Error: can't create $outputTrsDirectory"
+	return false;
+}
+
+boolean ok = true
+for (File trsFile : files) {
+	
+	if (!trsFile.getName().toLowerCase().endsWith(".trs")) continue;
+	
+	File outputTrsFile = new File(outputTrsDirectory, trsFile.getName());
+	
+	ok = ok && gse.runMacro(RenameSpeakerMacro, ["trsFile":trsFile, "outputTrsFile":outputTrsFile, "idRegex":idRegex, "nameRegex":nameRegex, "newID":newID, "newName":newName])
+}
+
+return ok
\ No newline at end of file
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/transcriber/ChangeSpeaker.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/transcriber/ChangeSpeaker.groovy	(revision 3016)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/transcriber/ChangeSpeaker.groovy	(revision 3017)
@@ -1,148 +0,0 @@
-// Copyright © 2010-2013 ENS de Lyon.
-// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
-// Lyon 2, University of Franche-Comté, University of Nice
-// Sophia Antipolis, University of Paris 3.
-// 
-// The TXM platform 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 2 of the License, or (at your option) any
-// later version.
-// 
-// The TXM platform 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 the TXM platform. If not, see
-// http://www.gnu.org/licenses.
-// 
-// 
-// 
-// $LastChangedDate:$
-// $LastChangedRevision:$
-// $LastChangedBy:$ 
-//
-package org.txm.scripts.importer.transcriber;
-
-import org.txm.scripts.importer.*;
-import org.txm.utils.*;
-import org.txm.metadatas.*;
-
-import java.io.File;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import javax.xml.parsers.*;
-import javax.xml.xpath.*;
-import javax.xml.transform.*;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-
-// TODO: Auto-generated Javadoc
-/** remove part of xml given an id. */
-public class ChangeSpeaker {
-	File outfile;
-	
-	/** The doc. */
-	Document doc;
-	
-	/**
-	 * Instantiates a new change speaker.
-	 *
-	 * @param transcriptionfile the transcriptionfile
-	 * @param outfile the outfile
-	 * @param id the id
-	 * @param newid the newid
-	 */
-	public ChangeSpeaker(File transcriptionfile, File outfile, String id, String newid)
-	{
-		this.outfile = outfile;
-		
-		String xpath = "//Turn";
-		DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
-		domFactory.setNamespaceAware(true); // never forget this!
-		domFactory.setXIncludeAware(true);
-		DocumentBuilder builder = domFactory.newDocumentBuilder();
-		doc = builder.parse(transcriptionfile);
-		
-		def expr = XPathFactory.newInstance().newXPath().compile(xpath);
-		def nodes = expr.evaluate(doc, XPathConstants.NODESET);
-		
-		
-		
-		for(def node : nodes)
-		{
-			if (node == null) continue;
-			
-			Element elem = (Element)node;
-			if(elem.getAttribute("speaker").contains(id))
-			{
-				String value = elem.getAttribute("speaker");
-				value = value.replace(id, newid);
-				elem.setAttribute("speaker", value);
-			}
-		}
-		
-		def expr2 = XPathFactory.newInstance().newXPath().compile("//Speaker[@id='"+id+"']");
-		def nodes2 = expr2.evaluate(doc, XPathConstants.NODESET);
-		
-		for(def node : nodes2)
-		{
-			if (node == null) continue;
-			
-			Element elem = (Element)node;
-			elem.setAttribute("id", newid);
-		}
-		save()
-	}
-	
-	/**
-	 * Save.
-	 *
-	 * @return true, if successful
-	 */
-	private boolean save()
-	{
-		try {
-			// Création de la source DOM
-			Source source = new DOMSource(doc);
-			
-			// Création du fichier de sortie
-			Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outfile), "UTF-8")); 
-			Result resultat = new StreamResult(writer);
-			
-			// Configuration du transformer
-			TransformerFactory fabrique = new net.sf.saxon.TransformerFactoryImpl();
-			Transformer transformer = fabrique.newTransformer();
-			transformer.setOutputProperty(OutputKeys.METHOD, "xml");
-			transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 
-			transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); 
-			
-			// Transformation
-			transformer.transform(source, resultat);
-			writer.close();
-			return true;
-		} catch (Exception e) {
-			org.txm.utils.logger.Log.printStackTrace(e);
-			return false;
-		}
-	}
-	
-	/**
-	 * The main method.
-	 *
-	 * @param args the arguments
-	 */
-	public static void main(String[] args)
-	{
-		String homedir = System.getProperty("user.home")
-		File trs1 = new File(homedir, "xml/concattrs/int18_1.trs")
-		new ChangeSpeaker(trs1, trs1, "spk2", "spk4");
-		new ChangeSpeaker(trs1, trs1, "spk3", "spk2");
-		new ChangeSpeaker(trs1, trs1, "spk4", "spk3");
-	}
-}
