Выполняем работу iTunes 😉 Помнится в нём была подобная функциональность — набить айпод произвольной музыкой из библиотеки под завязку. Впрочем тут условия чуть сложнее 🙂
SG8-SongList.ps1
# Загружаем содержимое файла songlist.csv. Import-Csv использовать не получится, # так как он берет заголовки из первой строки, а в этом файле заголовков нет, и # в первой строке находятся данные. $Songs = Get-Content "c:\scripts\songlist.csv" | # Отбираем только строки попадающие под регулярное выражение, заодно # разбирая на группы. where {$_ -match "^(.+),(.+),(.+)$"} | foreach { # Создаем новый, пустой объект. $obj = New-Object "PSObject" # Добавляем к нему свойства со значениями полученными из регулярного # выражения ($Matches). $obj | Add-Member "noteproperty" -Name "Artist" -Value $matches[1] $obj | Add-Member "noteproperty" -Name "Song" -Value $matches[2] # Добавляя свойство Time, преобразовываем значение в тип [TimeSpan] # (отрезок времени). $obj | Add-Member "noteproperty" -Name "Time" -Value ([TimeSpan]("0:"+$matches[3])) # Выводим полученный объект на конвейер. $obj } # В результате в переменной $Songs у нас содержится массив объектов со # свойствами Artist, Song, Time. # Создаем массив $Burnlist, это список песен для записи. $Burnlist = @() # Создаем объект класса Random для генерации произвольных чисел. $r = New-Object random # Запускаем бесконечный цикл. while ($true) { # Получаем произвольную песню из списка. $song = $Songs[$r.next($Songs.length)] # Если в списке $BurnList содержится не более одной песни от $Song.Artist и # в списке еще нет конкретно этой песни... if ((($burnlist | where {$_.artist -eq $song.artist}).count -le 1) ` -and (!($burnlist | where {$_.song -eq $song.song}))) { # Добавляем к списку записи $Song $Burnlist += $song # Считаем какова общая продолжительность песен в $Burnlist: # Создаем переменную $n класса [TimeSpan] [timespan]$n=0 # Добавляем к $n время всех треков из $BurnList $burnlist |%{$n+=$_.time} # Если суммарное время превышает 80 минут, то обнуляем $Burnlist, и он # будет заполняться заново. Не самый оптимальный алгоритм, но... 🙂 if ($n -gt [timespan]::FromMinutes(80)){$Burnlist = @()} # Если суммарное время удовлетворяет условиям задачи (Больше 75 минут и # меньше 80)... if ($n -lt [timespan]::FromMinutes(80) -and $n -gt [timespan]::FromMinutes(75)) { # Cортируем список по исполнителю. $Burnlist | Sort artist | # Выбираем свойства Artist и Song, а свойство Time заменяем # текстовым (вместо [TimeSpan]) с временем в формате который # предпочитают Scripting Guys 🙂 Select Artist, Song, @{n="Time";e={$_.Time -replace "^00:"}} | # Выводим объекты на GridView Out-GridView # Пишем сколько всего времени заняли треки на диске. Write-Host "Total music time: $([int]$n.totalminutes):$($n.seconds)" # Завершаем работу скрипта. Exit } } }
Опять далеко не идеал 😉 Другие варианты: Mow, Per Østergaard, Scripting Guys, Macro Shaw.
PS: Срочно в номер 🙂 Через полтора-два часа (12 MSK) начнется очень интересный вебкаст, рекомендую записаться и посмотреть 😉
13.3.2008 в 15:06
Мое решение…
$Grp = @{}
$Album = @()
$Complite = $false
$Total = [TimeSpan] «0:00»
$RndGen = New-Object Random
$Songs = Get-Content C:\Scripts\songlist.csv
$C = $Songs.Count
while (!$Complite)
{
$I = $RndGen.Next($C)
$S = $Songs[$I]
$SS = $S.Split(«,»)
$TT = $Total.Add(«0:»+$SS[2])
if (($Grp[$SS[0]] -lt 2) -and ($Album -notcontains $I) -and ($TT.TotalMinutes -le 80.0))
{
$Album+=$I
$Grp[$SS[0]]=$Grp[$SS[0]]+1
$Total = $TT
$Complite = ($Total.TotalMinutes -ge 75.0) -and ($Total.TotalMinutes -le 80.0)
}
}
» ARTIST SONG TIME»
«-«*79
$Album | ForEach-Object {$T=$Songs[$_].Split(«,»);$A=$T[0].PadRight(30);$S=$T[1].PadRight(35);$M=$T[2].PadRight(6);»$A $S $M»} | Sort
«»
«Total music time: «+[int]$Total.TotalMinutes+»:»+$Total.Seconds.ToString().PadLeft(2,»0″)
Врядли тоже самое оптимальное.