【问题标题】:AppleScript to add multiple tracks from iTunes into a playlist using a text file as the sourceAppleScript 使用文本文件作为源将 iTunes 中的多个曲目添加到播放列表中
【发布时间】:2016-09-11 06:13:21
【问题描述】:

我有一个 iTunes 播放列表,我之前已备份到一个文本文件中,该文件格式如下:

“标题”、“艺术家”、“曲目编号”、“专辑”

我使用其中四个轨道创建了一个示例文件:

“Ritual”、“Chick Corea Elektric Band II”、“9”、“Paint The World”
“风险”、“Deftones”、“9”、“钻石眼”
"Risveglio","Goblin","10","Zombi"
“Ritual”、“Ashes Divide”、“8”、“不断告诉自己没关系”

此播放列表中的所有曲目当前都在 iTunes 中。我想使用 AppleScript 将这些曲目中的每一个添加到播放列表中。我已经能够使用以下 AppleScript 对单个项目(例如:标题)进行操作:

-- set variables
set srcFile to "/Users/kjesso/Documents/=Scripting=/AppleScript/ipod_gym_playlist_track_names_sample.txt"
set allRecords to paragraphs of (read srcFile as «class utf8»)
set myPlaylist to "Test"
property okflag : false

-- check if iTunes is running
tell application "Finder"
    if (get name of every process) contains "iTunes" then ¬
        set okflag to true
end tell
if okflag then
    -- if iTunes is running then do this
    tell application "iTunes"
        repeat with aRecord in allRecords
            set results to (every file track of playlist "Library" whose name is aRecord)
            repeat with aTrack in results
                duplicate aTrack to playlist myPlaylist
            end repeat
        end repeat
    end tell
else
    -- if iTunes is not running do this
    return "Unable to execute because iTunes is not running"
end if

但是,如果发现来自不同艺术家的重复曲目标题,它将只使用第一首曲目,因为脚本无法区分仅以“标题”作为内容的不同艺术家。 AppleScript 中是否原生存在数组?

我认为这需要使用属性列表文件来完成?在网上进一步阅读后,尝试创建一个数组来做我想做的事情(捕获曲目标题、艺术家、专辑等),我遇到了各种线程like this 说最好使用属性列表?我正在尝试实现类似于 here 所做的工作,但我不想将输出发送到 CSV 文件,而是将其发送到 iTunes 中的播放列表。

如果我需要使用属性列表来实现我的目标,我创建了以下示例属性列表文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>title</key>
    <string>"Ritual"</string>
    <key>artist</key>
    <string>"Chick Corea Elektric Band II"</string>
    <key>album</key>
    <string>"Paint The World"</string>
</dict>
<dict>
    <key>title</key>
    <string>"Risk"</string>
    <key>artist</key>
    <string>"Deftones"</string>
    <key>album</key>
    <string>"Diamond Eyes"</string>
</dict>
<dict>
    <key>title</key>
    <string>"Risveglio"</string>
    <key>artist</key>
    <string>"Goblin"</string>
    <key>album</key>
    <string>"Zombi"</string>
</dict>
<dict>
    <key>title</key>
    <string>"Ritual"</string>
    <key>artist</key>
    <string>"Ashes Divide"</string>
    <key>album</key>
    <string>"Keep Telling Myself It's Alright"</string>
</dict>
</plist>

有人对如何让它工作有任何想法吗?

【问题讨论】:

    标签: applescript itunes playlist property-list


    【解决方案1】:

    如果您希望选择不仅基于名称,还基于艺术家、专辑...只需添加过滤器,如下例所示。

    另外,您可能不需要检查 iTunes 是否打开。当脚本运行时,如果 iTunes 没有启动,脚本将直接启动它。所以除非你真的不希望它自动打开 iTunes,否则什么都不做。

    通常,您不需要参考特定的播放列表“库”。这是默认值。

    set myPlaylist to "Test"
    set {theTitle, theAlbum, theArtist} to {"Ritual", "Paint The World", "Chick Corea Elektric Band II"}
    
    tell application "iTunes"
    set myTracks to (tracks whose (name is theTitle) and (album is theAlbum) and (artist is theArtist))
    duplicate (item 1 of myTracks) to playlist myPlaylist
    end tell
    

    我假设只有 1 首曲目匹配标题、专辑和艺术家(然后我拿了第一个也是唯一找到的项目)。如果您不确定它是否足够,您可以在过滤器中添加其他内容(年份、持续时间...)。

    关于 plist 或文本文件或记录列表,请记住,关键是您使用相同的方法来写入和读取文件。所以正确的问题是:您是如何编写该文件的? (我猜不是手动的!)

    如果您是从另一个脚本构建文件,那么保存和读取记录会容易得多(一个记录={title,album,artist})。除了在脚本中读写之外,您将无事可做。唯一的缺点是您将无法使用文本编辑器读取文件……但这是必需的?

    在下面的示例中,脚本从 txt 文件(与您的示例相同)中读取,每行 1 个轨道,每个值由 ',' 分隔:

    set textFile to choose file "Select your text file"
    set myText to (paragraphs of (read textFile))
    set AppleScript's text item delimiters to {","}
    set myRecords to {}
    repeat with aParagraph in myText
    set MS to aParagraph as string
    if (count of (text items of MS)) is 4 then
        set the end of myRecords to {text item 1 of MS, text item 2 of MS, text item 3 of MS, text item 4 of MS}
    else
        -- skipt the record : invalid number of text item !
    end if
    end repeat
    

    结果是一个 myRecords 列表,每条记录是一个由 4 个值组成的列表 {title,artist,trackNo,album}

    【讨论】:

    • 感谢您的回复,但是,如果我正确理解您的回答,此解决方案的问题是我必须将所有曲目的全部内容放入 AppleScript 中,目前所有曲目都在在文本文件或 csv 文件中。如果它只是像我的示例中的几个轨道,这个解决方案会很好,但我实际上有几百个,因此我尝试通过脚本执行此操作的原因。至于 plist 文件,我是使用带有正则表达式的文本编辑器创建的,所以组合起来并不难,但我也可以用脚本来完成。
    • 如果有一种方法可以从源文本或 csv 文件中捕获“theTitle”、“theAlbum”和“theArtist”的值,这个解决方案会很好用,这会回到我原来的状态问题。
    • 我只是在我的第一个答案中添加了从文本文件中读取的示例。
    • 谢谢@pbell,我明天会分析你的解决方案,看看我是否会重复我想要的。我不确定我是否可以做一个数组,但是在你的答案中看到这条线“将 {theTitle, theAlbum, theArtist} 设置为 {"Ritual", "Paint The World", "Chick Corea Elektric Band II"}"这让我再次想到了数组,所以我开始搜索 AppleScript 数组的示例,并遇到了this post,它帮助我找到了原始解决方案中缺失的部分。
    【解决方案2】:

    我最终在this post 的帮助下使用一维数组(列表)自己找到了解决方案。这是最终结果:

    set srcFile to "/Users/kjesso/Documents/=Scripting=/AppleScript/ipod_mp3s_sample.csv"
    set allRecords to paragraphs of (read srcFile as «class utf8»)
    set myPlaylist to "Test"
    
    tell application "iTunes"
        repeat with aRecord in allRecords
            set AppleScript's text item delimiters to ","
            set arrayVar to text items of aRecord
            set results to (every file track of playlist "Library" whose name is (item 1 of arrayVar) and artist is (item 2 of arrayVar) and track number is (item 3 of arrayVar) and album is (item 4 of arrayVar))
            repeat with aTrack in results
                duplicate aTrack to playlist myPlaylist
            end repeat
        end repeat
    end tell
    

    这里是源文件“ipod_mp3s_sample.csv”的内容:

    Ritual,Ashes Divide,8,Keep Telling Myself It's Alright
    Ritual,Chick Corea Elektric Band II,9,Paint The World
    Risk,Deftones,9,Diamond Eyes
    Risveglio,Goblin,10,Zombi
    

    【讨论】:

      【解决方案3】:

      这是我编写的一个脚本,它接收一个带有 Track/Artist TAB 分隔的 CSV 文件。 我用它从我在 Spotify 上找到的播放列表中搜索我自己的 iTunes 库。
      我使用了一个在线导出器,将您的 Spotify 播放列表导出为 CSV。 我必须先清理 excel 中的播放列表。

      这也创建了单独的日志文件:

      1) 找到的曲目
      2) 没有找到的曲目
      (我将此列表用于我拥有的单独脚本
      然后会在 soulSeek 上为我搜索这些歌曲)

      代码如下:

      -- Choose a file
      set CSVstr to "Please locate your CSV file..."
      set CSV_File to (choose file with prompt CSVstr) as text
      set posixfilepath to (the POSIX path of CSV_File)
      set posixfilepathLIST to emptylist(stringtolist(posixfilepath, "/"))
      --set thename to item 1 of stringtolist(last item of posixfilepathLIST, ".")
      set thename to (ListToString((reverse of (rest of (reverse of (stringtolist(last item of posixfilepathLIST, "."))))), "."))
      set posixfilepathLISTCLEANED to reverse of (rest of (reverse of posixfilepathLIST))
      set posixfilepathSTRINGCLEANED to ListToString(posixfilepathLISTCLEANED, ":")
      
      --creates log file
      set log_file_found to posixfilepathSTRINGCLEANED & ":" & (thename) & "_Matched_in_iTunes.txt"
      global log_file_found
      ClearLog(log_file_found)
      WriteLog("Program Started....")
      set log_file_notfound to posixfilepathSTRINGCLEANED & ":" & (thename) & "_NotFound_in_iTunes.txt"
      global log_file_notfound
      ClearLog(log_file_notfound)
      WriteLog2("Program Started....")
      property dialog_timeout : 3 -- set the amount of time before dialogs auto-answer.
      
      -- Reading your file to memory
      set CSV_Lines to every paragraph of (read file CSV_File from 1)
      set AppleScript's text item delimiters to {""}
      set Line_Values to {}
      set {tids, text item delimiters} to {text item delimiters, "    "}
      set trackCount to (count CSV_Lines)
      set foundCount to 0
      set NotfoundCount to 0
      set gov to 1
      
      
      tell application "iTunes"
          try
              set opt to (display dialog "Enter Name for Playlist" default answer {thename} default button 2 with title " Spotify Recreate from CSV " with icon 1)
              set newName to (text returned of opt)
              set maxfind to (button returned of opt)
              if newName is "" then error
          on error
              return
          end try
      
          try
              set newnom to ("_WrangledFrom_" & newName)
              if exists playlist newnom then delete playlist newnom
              set newP to (make new playlist with properties {name:newnom})
              set thePlaylist to view of the front browser window
              set view of front window to newP
              set listOfNames to {}
              set listOfNamesNotFound to {}
          end try
      end tell
      
      
      
      -- moves through the list one item at a time
      repeat with i from 1 to trackCount
          set savedTIDS to AppleScript's text item delimiters
          set searchName to text item 1 of item i of CSV_Lines
          set searchArtist to text item 2 of item i of CSV_Lines
          set searchAll to (searchName & " - " & searchArtist) as text
          set searchAll2 to (searchName & " " & searchArtist) as text
          set tid to AppleScript's text item delimiters
      
          #insert routine here:
          tell application "iTunes"
      
      
              --ignoring diacriticals and punctuation
              --set big_list to (every file track whose name contains {searchName} and artist contains {searchArtist})
              --set big_list to (every file track of playlist "Library" whose name contains searchName and artist contains searchArtist)
              set big_list to (search library playlist 1 for {searchAll2} only songs)
              --set search_results to (search library playlist 1 for searchAll2)
              --set results to (every file track of playlist "Library" whose name contains searchName and artist contains searchArtist)
              --end ignoring
      
              set foundtracks to (count of items of big_list)
              if (count of items of big_list) is greater than or equal to gov then
                  set foundCount to foundCount + 1
                  set foundtrackinfo to ("Found " & foundtracks & " For | " & searchAll)
                  delay 0.2
                  my WriteLog(foundtrackinfo)
                  copy foundtrackinfo to the end of listOfNames
      
                  repeat with a in big_list
                      duplicate a to newP
                  end repeat
              else
                  set NotfoundCount to NotfoundCount + 1
                  set foundtrackinfo to ("Not Found | " & searchAll) as text
                  delay 0.1
                  my WriteLog2(foundtrackinfo)
                  copy foundtrackinfo to the end of listOfNamesNotFound
              end if
          end tell
      end repeat
      delay 2
      tell application "iTunes"
          set view of front window to newP
      end tell
      delay 2
      try
          tell application "System Events"
              tell process "iTunes"
                  set frontmost to true
              end tell
      
              keystroke "a" using {control down, option down, command down}
              delay 1
              keystroke "a" using {option down, command down}
              delay 1
          end tell
      end try
      
      set AppleScript's text item delimiters to savedTIDS
      set AppleScript's text item delimiters to {""}
      
      display dialog ("Spotify CSV Wrangle Complete") buttons {"OK"} default button 1
      my WriteLog("Program Ended...")
      my WriteLog2("Program Ended...")
      
      on WriteLog(text4Log)
          set wri to open for access file log_file_found with write permission
          write (text4Log & return) to wri starting at eof
          close access wri
      end WriteLog
      
      on WriteLog2(text4Log)
          set wri to open for access file log_file_notfound with write permission
          write (text4Log & return) to wri starting at eof
          close access wri
      end WriteLog2
      
      on ClearLog(clear_log_file)
          set clearLF to open for access file clear_log_file with write permission
          set eof of clearLF to 0
          close access clearLF
      end ClearLog (*
          --Progress Bar Subroutine
      
          --my SetupProgress([[linked-template:text]], 0, "Processing Data...", "Preparing to process.")
      
          on SetupProgress(SPTotalCount, SPCompletedSteps, SPDescription, SPAdditionalDescription)
              set progress total steps to {SPTotalCount}
              set progress completed steps to {SPCompletedSteps}
              set progress description to {SPDescription}
              set progress additional description to {SPAdditionalDescription}
          end SetupProgress
      
      *)
      
      on emptylist(klist)
          set nlist to {}
          set dataLength to length of klist
          repeat with i from 1 to dataLength
              if item i of klist is not "" then
                  set end of nlist to (item i of klist)
              end if
          end repeat
          return nlist
      end emptylist
      
      on ListToString(theList, delim)
          set oldelim to AppleScript's text item delimiters
          set AppleScript's text item delimiters to delim
          set alist to theList as string
          set AppleScript's text item delimiters to oldelim
          return alist
      end ListToString
      
      on stringtolist(theString, delim)
          set oldelim to AppleScript's text item delimiters
          set AppleScript's text item delimiters to delim
          set dlist to (every text item of theString)
          set AppleScript's text item delimiters to oldelim
          return dlist
      end stringtolist
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-08
        • 1970-01-01
        • 2013-09-11
        • 2012-09-22
        • 1970-01-01
        相关资源
        最近更新 更多