I'm working on a little coding project for my own enjoyment, and I'm stumped by a problem of sorts. I have working code for now, but I know it could be cleaned up. Essentially, I'm trying to take an array of objects, and only return unique elements that meet certain criteria.
With this example data:
[{
"title": "1. Title of first song",
"file": {
"url": "https://mediafiles.abc/files/media_E_001_r720P.mp4",
"modifiedDatetime": "2019-02-06 03:40:52"
},
"filesize": 44043684,
"trackImage": {
"url": "https://mediafiles.abc/files/media_E_001.jpg",
"modifiedDatetime": "2021-03-15T12:34:06+00:00"
},
"mimetype": "video/mp4",
"subtitled": false,
"frameWidth": 1280,
"frameHeight": 720,
"duration": 233.29973333333334
},
{
"title": "1. Title of first song",
"file": {
"url": "https://mediafiles.abc/files/media_E_001_r240P.mp4",
"modifiedDatetime": "2019-02-06 03:40:52"
},
"filesize": 653534,
"trackImage": {
"url": "https://mediafiles.abc/files/media_E_001.jpg",
"modifiedDatetime": "2021-03-15T12:34:06+00:00"
},
"mimetype": "video/mp4",
"subtitled": false,
"frameWidth": 320,
"frameHeight": 240,
"duration": 233.29973333333334
},
{
"title": "2. Title of second song",
"file": {
"url": "https://mediafiles.abc/files/media_E_002_r240P.mp4",
"modifiedDatetime": "2019-02-06 03:40:52"
},
"filesize": 45456456,
"trackImage": {
"url": "https://mediafiles.abc/files/media_E_002.jpg",
"modifiedDatetime": "2021-03-15T12:34:06+00:00"
},
"mimetype": "video/mp4",
"subtitled": false,
"frameWidth": 320,
"frameHeight": 240,
"duration": 233.29973333333334
},
{
"title": "2. Title of second song",
"file": {
"url": "https://mediafiles.abc/files/media_E_002_r720P.mp4",
"modifiedDatetime": "2019-02-06 03:40:52"
},
"filesize": 3453453,
"trackImage": {
"url": "https://mediafiles.abc/files/media_E_002.jpg",
"modifiedDatetime": "2021-03-15T12:34:06+00:00"
},
"mimetype": "video/mp4",
"subtitled": true,
"frameWidth": 1280,
"frameHeight": 720,
"duration": 233.29973333333334
},
{
"title": "3. Title of third song",
"file": {
"url": "https://mediafiles.abc/files/media_E_003_r240P.mp4",
"modifiedDatetime": "2019-02-06 03:40:52"
},
"filesize": 45456456,
"trackImage": {
"url": "https://mediafiles.abc/files/media_E_003.jpg",
"modifiedDatetime": "2021-03-15T12:34:06+00:00"
},
"mimetype": "video/mp4",
"subtitled": false,
"frameWidth": 320,
"frameHeight": 240,
"duration": 233.29973333333334
},
{
"title": "3. Title of third song",
"file": {
"url": "https://mediafiles.abc/files/media_E_003_r720P.mp4",
"modifiedDatetime": "2019-02-06 03:40:52"
},
"filesize": 3453453,
"trackImage": {
"url": "https://mediafiles.abc/files/media_E_003.jpg",
"modifiedDatetime": "2021-03-15T12:34:06+00:00"
},
"mimetype": "video/mp4",
"subtitled": true,
"frameWidth": 1280,
"frameHeight": 720,
"duration": 233.29973333333334
},
{
"title": "3. Title of third song",
"file": {
"url": "https://mediafiles.abc/files/media_E_003_r720P.mp4",
"modifiedDatetime": "2019-02-06 03:40:52"
},
"filesize": 3453453,
"trackImage": {
"url": "https://mediafiles.abc/files/media_E_003.jpg",
"modifiedDatetime": "2021-03-15T12:34:06+00:00"
},
"mimetype": "video/mp4",
"subtitled": false,
"frameWidth": 1280,
"frameHeight": 720,
"duration": 233.29973333333334
},
{
"title": "3. Title of third song",
"file": {
"url": "https://mediafiles.abc/files/media_E_003_r1080P.mp4",
"modifiedDatetime": "2019-02-06 03:40:52"
},
"filesize": 15611561561,
"trackImage": {
"url": "https://mediafiles.abc/files/media_E_003.jpg",
"modifiedDatetime": "2021-03-15T12:34:06+00:00"
},
"mimetype": "video/mp4",
"subtitled": false,
"frameWidth": 1920,
"frameHeight": 1080,
"duration": 233.29973333333334
}
]
I would like to filter this down and return a somewhat trimmed-down version of the 1st, 4th and 7th elements. My criteria is the following:
- Discard elements with a frameHeight higher than a user-specified value (in this example, we'll assume that this value is 720)
- Only return unique (based on title) elements in final set
- Keep highest resolution items (based on frameHeight)
- Prefer non subtitled media if possible (ie, if both subtitled and non-subtitled element exist at the highest allowed resolution, keep only non-subtitled element)
In addition, I'd like the return array's objects to include only 4 keys: "title", "url" (which would be mapped from file.url), "filesize", and "duration"
I've tried various things so far, including:
- sorting the array based on each element's frameHeight in descending order, then
- looping over the sorted array and pushing values into a new array if title doesn't exist in array, then
- filtering out subtitled versions for each element, but only if a non-subtitled version is present at that item's resolution.
As you can tell, what I have so far is messy and very ... inelegant.
Here it is:
// data is my data, reverse sorted by frameHeight
function getMediaInfo(data) {
let mediaFiles = [];
for (var mediaFileItem of data) {
if ((mediaFileItem.frameHeight !== 0 && mediaFileItem.frameHeight > prefs.maxRes) || mediaFiles.filter(mediaFile => {
return mediaFile.title == mediaFileItem.title && mediaFile.subtitled == mediaFileItem.subtitled
}).length > 0) {
continue;
} else {
mediaFiles.push({
title: mediaFileItem.title,
filesize: mediaFileItem.filesize,
url: mediaFileItem.file.url,
subtitled: mediaFileItem.subtitled,
duration: mediaFileItem.duration
});
}
}
if (mediaFiles.length > 1) mediaFiles = mediaFiles.filter(mediaFile => !mediaFile.subtitled);
return mediaFiles.reverse();
}
I would like to use some sort of combination of filter, map and reduce, but quite frankly I'm not sure where to start.
I'm not sure if one reduce could manage all that, or if I would need to chain a few things together. In any case, I'm looking for something clean and elegant, not a bunch of for loops like I have at the moment.
I'll appreciate any insight into how to best approach this. Right now like I said... I'm stumped.
Thank you all!