Page 1 of 11

ExtractFields v0.1.4 [MM2+3]

Posted: Tue Jun 13, 2006 2:13 pm
by Steegy
:: ExtractFields


The ExtractFields script lets you change tags/fields using the contents of the existing tags.

Typically, this script is used to split titles received from FreeDB (when they contain Title - Artist), to copy or swap fields, to remove leading track numbers, ...


You can use different "entry lines". Each entry line gets/puts it's information from/in the specified information field (chosen from the dropdown list). The mask that you specify will make sure that the chosen information field gets parsed and the other fields are filled with the info, or that the chosen information field will be filled like specified in the mask.

This script is generally applicable and can be used to replace scripts like:
- SwapArtistTitle
- SwitchOrCopyFields
- Split Artist Title
and maybe other.

The script can be accessed through menu Tools > Scripts > "Extract Fields...", or from the button added to the standard toolbar.
The default shortcut key is Ctrl+Alt+X

When the "Extract Fields" button is clicked, the selected songs *at that moment* are used (not the songs that were selected before you opened the form). So you can still change the songs selection while the form is open.

The "USER DEFAULTS" section on top of the script contains default values that are used when the script starts. You can change this yourself.
Make sure that def_TagField contains a value mentioned in SongDataFields (bottom of the script), and that def_TagMask is a mask that can contain variables mentioned in CommonTags (bottom of the script).

The script needs MediaMonkey version 2.5.3 or above.

Installing manually:

The script below is an auto-script. The Faq "How do I install scripts?" ... artlang=en explains how to install it.
Quicky: Copy the code below to a plain text file (e.g. using NotePad) and save it as ExtractFields.vbs. Put that file in MediaMonkey's Scripts\Auto folder and (re)start MediaMonkey.

The script consists of 1 standalone script file ("ExtractFields.vbs")

ExtractFields.vbs (for the Scripts\Auto folder)

Code: Select all

' MEDIAMONKEY SCRIPT: ExtractFields v0.1.4 (last updated 2007-08-17)    by   Steegy
'  Change tags/fields using the contents of the existing tags.
Option Explicit

'****                USER DEFAULTS                ****

Const def_EntryLinesCnt = 2
Const def_TagField = "Title"
Const def_TagMask = "%A - %S"

'****              SCRIPT PROPERTIES              ****

Const RequiredMMVersion = 253
Const ScriptName = "ExtractFields"
Const ScriptCaption = "Extract Fields..."
Const ScriptHint = "Change tags based on existing tags"
Const ScriptShortCut = "Ctrl+Alt+X"

'****             GLOBAL DECLARATIONS             ****

Dim Form, lblMasks, edtMasks, SpinEdit, lblPemTag, btnPem, lblPemValue, lblSpin, btnSpin, btnClose, btnExtractFields
Dim NumberOfEntryLines
Dim DataFieldsArray()
Dim MaskTextArray()
Dim EnableStateArray()
Dim DirectionArray()
Dim ParseEntryMethod

Const pemSerial = 1
Const pemParallel = 2

Dim FSO : Set FSO = CreateObject("Scripting.Filesystemobject")

'****                 ENTRY POINT                 ****

Sub OnStartup

    Dim CurrentVersion : CurrentVersion = SDB.VersionHi & SDB.VersionLo & SDB.VersionRelease

    If CurrentVersion < RequiredMMVersion Then
        Dim RequiredMMVersionString : RequiredMMVersionString = Mid(RequiredMMVersion, 1, 1) & "." & Mid(RequiredMMVersion, 2, 1) & "." & Mid(RequiredMMVersion, 3, 1)
        Dim Text
        Text = "'" & ScriptName & "' needs MediaMonkey " & RequiredMMVersionString & " or above." + vbNewLine
        Text = Text & "Please Download the latest Version on" & vbNewLine & vbNewLine
        SDB.MessageBox Text, mtError, Array(mbOK)
        Dim MenuItem : Set MenuItem = SDB.UI.AddMenuItem(SDB.UI.Menu_Scripts, 0, -1)
        MenuItem.Caption = ScriptCaption
        MenuItem.Hint = ScriptHint
        MenuItem.IconIndex = 25
        MenuItem.ShortCut = ScriptShortCut
        Script.RegisterEvent MenuItem, "OnClick", ScriptName
        Dim TBItem : Set TBItem = SDB.UI.AddMenuItem(SDB.UI.Menu_TbStandard, 0, -1)
        TBItem.Caption = ScriptCaption
        TBItem.Hint = ScriptHint
        TBItem.IconIndex = 25
        TBItem.ShortCut = ScriptShortCut
        Script.RegisterEvent TBItem, "OnClick", ScriptName
    End If

End Sub

Sub ExtractFields(MenuItem)

    Set Form = CreateForm("Change tags based on existing tags", 100, 100, 495, 140, bsDialog, poScreenCenter, True, "ExtractFields_Form")
    Set SDB.Objects("ExtractFields_Form") = Form
    Call CreateLabel(Form, "Enabled", 7, 15, 50, 20)
    Call CreateLabel(Form, "Field name", 85, 15, 60, 20)
    Call CreateLabel(Form, "Mask to recognise or tag", 280, 15, 120, 20)
    Set lblSpin = CreateLabel(Form, "Entry lines # :", 20, 0, 70, 20)
    Set SpinEdit = CreateSpinEdit(Form, 95, 0, 50, 20, "SpinEdit")
    SpinEdit.MinValue = 1
    SpinEdit.MaxValue = 15
    SpinEdit.Value = def_EntryLinesCnt
    Set btnSpin = CreateButton(Form, "Show", 150, 0, 50, 20, "btnSpin_OnClick")

    Set lblPemTag = CreateLabel(Form, "Entry parsing method :", 265, 0, 130, 20)

    Set lblPemValue = CreateLabel(Form, " ", 380, 0, 50, 20)
    lblPemValue.Caption = "Serial"
    ParseEntryMethod = pemSerial
    Set btnPem = CreateButton(Form, "Switch", 420, 0, 50, 20, "btnPem_OnClick")


    Set btnExtractFields = CreateButton(Form, "Extract Fields", 90, 0, 150, 20, "btnExtractFields_OnClick")
    btnExtractFields.Default = True

    Set btnClose = CreateButton(Form, "Close", 252, 0, 150, 20, "btnClose_OnClick")
    btnClose.Cancel = True
    Set lblMasks = CreateLabel(Form, "Usable mask fields :", 20, 0, 90, 20)
    Set edtMasks = CreateLabel(Form, SDB.Tools.Mask2UFText(ArrayToString(CommonTags, ", ")), 120, 0, 350, 50)
    edtMasks.Multiline = True
    NumberOfEntryLines = 0
    Call ChangeNumberOfEntryLines(def_EntryLinesCnt)
    Call SelectDropDownText(DataFieldsArray(0), def_TagField)
    MaskTextArray(0).Text = SDB.Tools.Mask2UFText(def_TagMask)
    EnableStateArray(0).Checked = True
    Form.Common.Visible = True

End Sub

Sub ChangeNumberOfEntryLines(NewNumber)

    Form.Common.Height = 200 + NewNumber * 25
    lblMasks.Common.Top = Form.Common.Height - 145
    edtMasks.Common.Top = Form.Common.Height - 158
    lblSpin.Common.Top = Form.Common.Height - 101
    SpinEdit.Common.Top = Form.Common.Height - 105
    lblPemTag.Common.Top = Form.Common.Height - 101
    lblPemValue.Common.Top = Form.Common.Height - 101
    btnPem.Common.Top = Form.Common.Height - 105
    btnSpin.Common.Top = Form.Common.Height - 105
    btnExtractFields.Common.Top = Form.Common.Height - 65
    btnClose.Common.Top = Form.Common.Height - 65

    Dim i
    If NewNumber < NumberOfEntryLines Then
        For i = NewNumber To NumberOfEntryLines - 1

            EnableStateArray(i).Common.Visible = False
            DataFieldsArray(i).Common.Visible = False
            MaskTextArray(i).Common.Visible = False
            DirectionArray(i).Common.Visible = False

        ReDim Preserve EnableStateArray(NewNumber - 1)
        ReDim Preserve DataFieldsArray(NewNumber - 1)
        ReDim Preserve MaskTextArray(NewNumber - 1)
        ReDim Preserve DirectionArray(NewNumber - 1)

        ReDim Preserve EnableStateArray(NewNumber - 1)
        ReDim Preserve DataFieldsArray(NewNumber - 1)
        ReDim Preserve MaskTextArray(NewNumber - 1)
        ReDim Preserve DirectionArray(NewNumber - 1)

        For i = NumberOfEntryLines To NewNumber - 1
            Dim chkEnabled : Set chkEnabled = CreateCheckBox(Form, " ", 20, 10 + 25*(i+1), 15, 20, "chkEnabled" & i)
            Dim ddnDataFields : Set ddnDataFields = CreateDropDown(Form, 55, 10 + 25*(i+1), 130, 20, "ddnDataFields" & i)
            ddnDataFields.Style = csDropDownList
            Call FillDropDownFromArray(ddnDataFields, SongDataFields)
            Dim btnChangeDirection : Set btnChangeDirection = CreateButton(Form, "-->", 192, 10 + 25*(i+1), 40, 20, "btnChangeDirection_OnClick")
            btnChangeDirection.Common.ControlName = "btnChangeDirection" & i
            Dim edtMaskText : Set edtMaskText = CreateEdit(Form, "", 240, 10 + 25*(i+1), 230, 15, "edtMaskText" & i)
            Set EnableStateArray(i) = chkEnabled
            Set DataFieldsArray(i) = ddnDataFields
            Set MaskTextArray(i) = edtMaskText
            Set DirectionArray(i) = btnChangeDirection
    End If

    NumberOfEntryLines = NewNumber
    ' Stupid, but the only way to get a redraw of the form (and so get correct displaying of the newly added controls)
    Form.Common.Visible = False
    Form.Common.Visible = True

End Sub

'****            EVENT HANDLING METHODS           ****

Sub btnChangeDirection_OnClick(Button)

    If Button.Caption = "-->" Then
        Button.Caption = "<--"
        Button.Caption = "-->"
    End If

End Sub

Sub btnPem_OnClick(btnPem)

    If ParseEntryMethod = pemSerial Then
        lblPemValue.Caption = "Parallel"
        ParseEntryMethod = pemParallel
        lblPemValue.Caption = "Serial"
        ParseEntryMethod = pemSerial
    End If

End Sub

Sub btnSpin_OnClick(btnSpin)

    Call ChangeNumberOfEntryLines(SpinEdit.Value)

End Sub

Sub btnClose_OnClick(btnClose)

    Form.Common.Visible = False
    Set Form = Nothing

End Sub

Sub btnExtractFields_OnClick(btnExtractFields)

    Dim SongList : Set SongList = SDB.CurrentSongList

    Dim Progress : Set Progress = SDB.Progress
    Progress.Text = SDB.Localize("Extracting and applying field information...")
    Progress.MaxValue = SongList.Count

    Dim i, j, Song, SongOrig, MaskTextInternal
    For i = 0 To SongList.Count - 1
        Progress.Text = SDB.Localize("Extracting and applying field information... (Track " & (i+1) & " of " & SongList.Count & ")")
        Set Song = SongList.Item(i)
        Set SongOrig = Song.GetCopy
        'Song.ArtistName = ""
        'Song.AlbumArtistName = ""
        For j = 0 To UBound(EnableStateArray)
            If EnableStateArray(j).Checked = True Then
                If DirectionArray(j).Caption = "-->" Then
                    MaskTextInternal = SDB.Tools.UFText2Mask(MaskTextArray(j).Text)
                    If ParseEntryMethod = pemSerial Then
                        Execute("Call Song.ParseText(Song." & DataFieldsArray(j).Text & ", MaskTextInternal)")
                    Else 'ParseEntryMethod = pemParallel
                        Execute("Call Song.ParseText(SongOrig." & DataFieldsArray(j).Text & ", MaskTextInternal)")
                    End If
                    MaskTextInternal = SDB.Tools.UFText2Mask(MaskTextArray(j).Text)
                    If ParseEntryMethod = pemSerial Then
                        Execute("Song." & DataFieldsArray(j).Text & " = Fillin(Song, MaskTextInternal)")
                    Else 'ParseEntryMethod = pemParallel
                        Execute("Song." & DataFieldsArray(j).Text & " = Fillin(SongOrig, MaskTextInternal)")
                    End If
                End If
            End If

        'If Song.ArtistName = "" Then Song.ArtistName = SongOrig.ArtistName
        'If Song.AlbumArtistName = "" Then Song.AlbumArtistName = SongOrig.AlbumArtistName
        Progress.Value = i + 1
    Call SongList.UpdateAll

End Sub

Function Fillin(Song, MaskTextInternal)

    Fillin = MaskTextInternal
    Dim key
    For Each key In FieldDict.Keys
        Call Execute("Fillin = Replace(Fillin, key, CStr(Song." & FieldDict(key) & "), 1, -1, 1)")

End Function

Function ArrayToString(SourceArray, SepChar)

    ArrayToString = SourceArray(0)
    Dim i
    For i = 1 To UBound(SourceArray)
        ArrayToString = ArrayToString & SepChar & SourceArray(i)
End Function

'****          CONTROLS UTILITY METHODS           ****

' BorderStyle constants
const bsNone = 0	'No border
const bsSizeable = 2	'Standard window (resizable)
const bsDialog = 3	'Dialog window (not resizable)
const bsToolWindow = 4	'Toolwindow (not resizable)
const bsSizeToolWin = 5	'Toolwindow (resizable)

' Position constants (for Forms)
const poDesigned = 0	 'Position and size specified by Left, Top, Width and Height
const poDefault = 1	 'Position and size determined by the operating system
const poScreenCenter = 4 'Centered on the screen

' DropDown Style constants
Const csDropDown = 0 	 'DropDown can be edited
Const csDropDownList = 2 'DropDown cannot be edited (user can only select from a list of values)

Function CreateForm(Caption, X, Y, Width, Height, BorderStyle, FormPosition, StayOnTop, SavePositionName)

    Set CreateForm = SDB.UI.NewForm
    CreateForm.Caption = Caption
    CreateForm.Common.SetRect X, Y, Width, Height
    CreateForm.BorderStyle = BorderStyle
    CreateForm.FormPosition = FormPosition
    CreateForm.StayOnTop = StayOnTop
    CreateForm.SavePositionName = SavePositionName

End Function

Function CreateDropDown(Owner, X, Y, Width, Height, ControlName)

    Set CreateDropDown = SDB.UI.NewDropDown(Owner)
    CreateDropDown.Common.SetRect X, Y, Width, Height
    CreateDropDown.Common.ControlName = ControlName

End Function

Function CreateEdit(Owner, Text, X, Y, Width, Height, ControlName)

    Set CreateEdit = SDB.UI.NewEdit(Owner)
    CreateEdit.Text = Text
    CreateEdit.Common.SetRect X, Y, Width, Height
    CreateEdit.Common.ControlName = ControlName

End Function

Function CreateSpinEdit(Owner, X, Y, Width, Height, ControlName)

    Set CreateSpinEdit = SDB.UI.NewSpinEdit(Owner)
    CreateSpinEdit.Common.SetRect X, Y, Width, Height
    CreateSpinEdit.Common.ControlName = ControlName
End Function

Function CreateButton(Owner, Caption, X, Y, Width, Height, OnClickHandler)

    Set CreateButton = SDB.UI.NewButton(Owner)
    CreateButton.Caption = Caption
    CreateButton.Common.SetRect X, Y, Width, Height
    If OnClickHandler <> "" Then
        Script.RegisterEvent CreateButton.Common, "OnClick", OnClickHandler
    End If

End Function

Function CreateLabel(Owner, Caption, X, Y, Width, Height)

    Set CreateLabel = SDB.UI.NewLabel(Owner)
    CreateLabel.Caption = Caption
    CreateLabel.Common.SetRect X, Y, Width, Height

End Function

Function CreateCheckBox(Owner, Caption, X, Y, Width, Height, ControlName)

    Set CreateCheckBox = SDB.UI.NewCheckBox(Owner)
    CreateCheckBox.Caption = Caption
    CreateCheckBox.Common.SetRect X, Y, Width, Height
    CreateCheckBox.Common.ControlName = ControlName
End Function

Sub SelectDropDownText(DropDown, Text)

    Dim i
    For i = 0 To DropDown.ItemCount - 1
        If DropDown.ItemText(i) = Text Then
            DropDown.ItemIndex = i
            DropDown.Text = Text
            Exit For
        End If
End Sub

Sub FillDropDownFromArray(DropDown, SourceArray)

    Dim i
    For i = 0 To UBound(SourceArray)
        DropDown.AddItem SourceArray(i)

End Sub

'****             EXTRA ENUMERATIONS              ****

Dim CommonTags : CommonTags = Array("%A", "%L", "%S", "%G", "%T", "%Y", "%X", "%R", "%C", "%M", "%B", "%U", "%V", "%W", "%P", "%F")

' Enumeration of the most important fields in the SongData object
Dim SongDataFields : SongDataFields = Array( _
        "AlbumArtistName", _
        "AlbumName", _
        "ArtistName", _
        "Author", _
        "Band", _
        "Bitrate", _
        "BPM", _
        "Comment", _
        "Conductor", _
        "Copyright", _
        "Custom1", _
        "Custom2", _
        "Custom3", _
        "Encoder", _
        "Genre", _
        "InvolvedPeople", _
        "Lyricist", _
        "Lyrics", _
        "MediaLabel", _
        "Mood", _
        "MusicComposer", _
        "Occasion", _
        "OriginalArtist", _
        "OriginalLyricist", _
        "OriginalTitle", _
        "OriginalYear", _
        "Publisher", _
        "Quality", _
        "Rating", _
        "Tempo", _
        "Title", _
        "TrackOrder", _
Dim FieldDict : Set FieldDict = CreateObject("Scripting.Dictionary") 
With FieldDict
  .Add "%A", "ArtistName"
  .Add "%C", "Author"
  .Add "%G", "Genre"
  .Add "%L", "AlbumName"
  .Add "%M", "BPM"
  .Add "%R", "AlbumArtistName"
  .Add "%S", "Title"
  .Add "%T", "TrackOrder"
  .Add "%U", "Custom1"
  .Add "%V", "Custom2"
  .Add "%W", "Custom3"
  .Add "%Y", "Year"
  .Add "%P", "Path"
End With


By default, the script starts with a mask that works the same way as the script "Split Artist Title" works. (to split "Artist - Title" titles received from FreeDB).


You can specify the number of "entry lines" you want to display. Each entry line is used to parse the track information field (from the dropdown) and save the matching information to other (or even the same) track information fields (from the mask). Each entry line can be enabled.

When you are using more than one entry line, the parsing can happen in two ways:
- Serial: each entry line is parsed after each other, so the second line parses the song that has already been changed by the first line.
- Parallel: each entry line parses with the same beginning information, so it doesn't depend on the previous entry lines.

Example 1: Serial vs. Parallel

Title = My Song Title
ArtistName = My Artist Name

entry line 1: On Title With mask <Artist>
entry line 2: On ArtistName With mask <Title>

- entry line 1 copies the contents of (the previous = original) Title "My Song Title" to ArtistName
- entry line 2 copies the contents of (the previous = already changed) ArtistName "My Song Title" to Title
---> Title = My Song Title
---> ArtistName = My Song Title

- entry line 1 copies the contents of (the original) Title "My Song Title" to Artist(Name)
- entry line 2 copies the contents of (the original) ArtistName "My Artist Name" to Title
---> Title = My Artist Name
---> ArtistName = My Song Title

--> So the "parallel" way lets you e.g. easily switch fields (as replacement of the SwapArtistTitle and SwitchOrCopyFields (in "switch" mode) scripts).
With only the one line like this, the script acts as the SwitchOrCopyFields script (in "copy" mode).

Example 2: Remove leading text

If you have a Title like "DragonMegaStore @ MyTitle" and want to change it to "MyTitle", then use one entry line:
entry line 1: On Title With mask <Skip> @ <Title>

Posted: Wed Jun 14, 2006 3:04 am
by trixmoto
Looks very powerful - I'm going to have fun playing! :)

Posted: Wed Jun 14, 2006 5:00 am
by Peke
Again, a pleasant suprise. The one of things I think I'll use daily :)

Posted: Wed Jun 14, 2006 5:40 am
by Bex
Looks very nice indeed. I'll check this one out when i get home.


Posted: Sun Jun 18, 2006 7:39 pm
by Nebbin
Is there any way, using this script, to copy data from any field TO the Publisher field? It's easy enough to use the Publisher field as a source, but if I understand correctly, it's currently not possible to use it as a mask?

Is there some other method or script that will help with copying data to the Publisher field? I have ~10,000 tracks to import into Traktor DJ 3, but Traktor doesn't recognise many of the fields used within MM. Publisher (Label) is one of the fields that is recognised by both, and I was hoping to make use of it to carry Album Artist names.

Obviously, I'm hoping to not do this manually ... :(

(Traktor has many deficiencies, tagging and file support being major ones, but it's audio quality - especially with tempo adjustment - is amazing.)

Posted: Mon Jun 19, 2006 4:07 am
by Steegy
Is there any way, using this script, to copy data from any field TO the Publisher field? It's easy enough to use the Publisher field as a source, but if I understand correctly, it's currently not possible to use it as a mask?
The default masks don't seem to support this indeed.
Support for all possible MM fields is the todo for this script.
The only thing I'm not sure of is if the devs will extend the masks to support all fields. If not, then no pain; the script will do it by itself then.

In the meantime, you can use my SwitchOrCopyFields script from

This script can copy or switch any available taggable field to another.


Posted: Thu Jul 13, 2006 3:59 am
by Speed Pete
On one of my PCs I use this script and it works perfect. But: I just tried it on my laptop, and I get an Error Message. I have the german version, and try to translate it:
"Error #438 - Runtime error in Microsoft VBScript
This Object does not support this propertiy or method.: 'SDB.Tools.Mask2UFText'
File: "MyPath\ExtractFields.vbs", line: 130, Column: 4 "

As somebody an idea?

Posted: Thu Jul 13, 2006 4:13 am
by trixmoto
This is probably because you're other machine does not have the latest version of MM installed.

Posted: Thu Jul 13, 2006 4:31 am
by Speed Pete
Damn! Thanks for your advice... :oops:

Small question...

Posted: Tue Aug 08, 2006 8:41 am
by MCSmarties
Steegy: How do I refer to the SongData objects that are not part of the specified "masks"?

I see that you referenced a lot of objects in the script but I don't know how to "call" them.

For example, if I wanted to switch "Year" and "Original Year", how do I do that?
I guess I need to run in "parallel" mode and specify

[enabled] Source field Year -> Mask <?????>
[enabled] Source field Original Year -> Mask <Year>

Using your older SwitchOrCopyFields script works for this since I can pick "Original Year" from the drop-down list,
but since you say this script is deprecated I'd rather use ExtractFields for everything.


Posted: Mon Sep 11, 2006 10:03 am
by RandallSG
I am trying to copy "ArtistName" into "AlbumArtist" where "AlbumArtist" is missing. This function works for me using this script when I copy other fields into "AlbumArtist", but for whatever reason does not seem to work specifically for "ArtistName".

ArtistName = "My Artist Name"
AlbumArtist = " "

entry line 1: On "Artist" With mask "<AlbumArtist>"

> entry line 1 should copy the contents of (the previous = original) ArtistName "My Artist Name" to "AlbumArtist

My results:
The scripts acts as if a change is made, and tags are even written. However, no changes are made. The end result is just as I started.
ArtistName = "My Artist Name"
AlbumArtist = " "

Again, I can use this same script to copy other fields into "AlbumArtist", but it does not work for me with "ArtistName".

Also, I do realize that there are other scripts I could use for this same functionality, but I am trying to avoid a proliferation of Scripts, and stick with the most flexible versions.

Posted: Thu Sep 14, 2006 1:28 pm
by RandallSG
RandallSG wrote:I am trying to copy "ArtistName" into "AlbumArtist" where "AlbumArtist" is missing. This function works for me using this script when I copy other fields into "AlbumArtist", but for whatever reason does not seem to work specifically for "ArtistName".
Anyone else with this same problem?

Posted: Fri Sep 15, 2006 3:03 am
by trixmoto
Do you have the album value filled in on these tracks?

Posted: Fri Sep 15, 2006 8:27 am
by RandallSG
Yes, Album is filled. I am just trying to copy Artist into AlbumArtist where AlbumArtist is missing.

It is odd, I can copy other <Masks> into AlbumArtist, but not Artist?

I can do it on a one-by-one basis, but that gets tedious very quickly.

could Comment be added as a mask?

Posted: Fri Sep 15, 2006 9:47 pm
by TequilaMitch
I want to copy my Mood and Occasion data to the Comment field, but "<Comment>" isn't one of the masks. Could this be easily added?

Also, is there a way to 'append' to the Comment field, instead of overwriting? I want to copy both the Mood and Occasion to the Comment field, not just one or the other. But with the script above, I don't think I could do that even if the <Comment> mask existed. First i'd copy the Mood into Comments, but then if I tried to copy Occasion into to Comments it would overwrite the Mood that I just copied there.

Any ideas?