Skip to content

Instantly share code, notes, and snippets.

@adrianseeley
Created July 23, 2017 16:43
Show Gist options
  • Save adrianseeley/c1abc1705007b1c4ca8006e8124db4c6 to your computer and use it in GitHub Desktop.
Save adrianseeley/c1abc1705007b1c4ca8006e8124db4c6 to your computer and use it in GitHub Desktop.
iTunes Custom Sort
const inFile = './Game.xml';
const outFileDiscover = './GameDiscover.xml';
const outFileExploit = './GameExploit.xml';
const fs = require('fs');
const regexIndexOf = (str, regex, end) => {
var match = str.match(regex);
return match.index + (end ? match[0].length : 0);
};
const stringBetween = (str, a, b) => {
const start = regexIndexOf(str, a, true);
const length = regexIndexOf(str, b) - start;
return str.substr(start, length);
};
const readTracks = (filename) => {
const file = fs.readFileSync(filename, 'utf8');
const trackBody = stringBetween(file, /<key>Tracks<\/key>\s*<dict>/, /<\/dict>\s*<key>Playlists<\/key>/);
const dictBodies = trackBody.split('<dict>');
const trackSections = dictBodies.filter(dictBody => {
return dictBody.indexOf('Track ID') !== -1;
});
const trackObjects = trackSections.map(trackSection => {
const trackId = trackSection.split('<key>Track ID</key><integer>')[1].split('</integer>')[0];
const playCount = trackSection.indexOf('<key>Play Count</key><integer>') === -1 ? 0 : trackSection.split('<key>Play Count</key><integer>')[1].split('</integer>')[0];
const skipCount = trackSection.indexOf('<key>Skip Count</key><integer>') === -1 ? 0 : trackSection.split('<key>Skip Count</key><integer>')[1].split('</integer>')[0];
return {
trackId: trackId,
playCount: playCount,
skipCount: skipCount,
trueCount: playCount - skipCount
};
});
return trackObjects;
};
const sortDiscover = (a, b) => {
if (a.skipCount == b.skipCount) {
return a.playCount - b.playCount;
} else {
return a.skipCount - b.skipCount;
}
};
const sortExploit = (a, b) => {
return b.trueCount - a.trueCount;
};
const generatePlaylistString = (trackObjects, sortLambda) => {
trackObjects.sort(sortLambda);
const playlistString = trackObjects.reduce((str, trackObject) => {
return str + '<dict><key>Track ID</key><integer>' + trackObject.trackId + '</integer></dict>';
}, '');
return playlistString;
};
const writePlaylist = (inFile, outFile, playlistString, name) => {
const file = fs.readFileSync(inFile, 'utf8');
const nameUpdatedFile = file.split('<key>Name</key><string>Game</string>').join('<key>Name</key><string>' + name + '</string>');
const listRemoved = nameUpdatedFile.split('<key>Playlist Items</key>')[0] + '<key>Playlist Items</key><array>';
const listInjected = listRemoved + playlistString + '</array></dict></array></dict></plist>';
fs.writeFileSync(outFile, listInjected, 'utf8');
};
const trackObjects = readTracks(inFile);
const playlistStringDiscover = generatePlaylistString(trackObjects, sortDiscover);
writePlaylist(inFile, outFileDiscover, playlistStringDiscover, 'GameDiscover');
const playlistStringExploit = generatePlaylistString(trackObjects, sortExploit);
writePlaylist(inFile, outFileExploit, playlistStringExploit, 'GameExploit');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment