Last active
June 18, 2018 17:11
-
-
Save kadamwhite/fda8a2c9b94f0ed372f2e401ca1e82b9 to your computer and use it in GitHub Desktop.
Paste into Dev Tools while running Plex to automatically work through your library and assign default album art.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var albumArt = (() => { | |
// Helpers | |
// (e.g. DOM shortcuts and class-checking utilities) | |
var qsa = ( container, selector ) => [ ...container.querySelectorAll( selector ) ]; | |
var nodeHasClass = ( node, str ) => node.classList.toString().indexOf( str ) > -1; | |
var whereNodeHasClass = ( str ) => ( node ) => nodeHasClass( node, str ); | |
var wherePropertyLike = ( obj, str ) => { | |
const key = Object.keys( obj ).find( key => key.indexOf( str ) > -1 ); | |
return key ? obj[ key ] : null; | |
}; | |
// Inspectors | |
// (e.g. find things out about the DOM) | |
var needsArt = ( node ) => qsa( node, 'i' ).reduce( ( hasPlaceholder, node ) => ( | |
hasPlaceholder || nodeHasClass( node, 'placeholderIcon' ) | |
), false ); | |
var getReactInstance = node => { | |
const key = Object.keys(node).filter(key => key.indexOf('react')>-1)[0]; | |
return node[ key ]; | |
}; | |
// Interactions | |
// (e.g. do things to the page) | |
var press = ( node ) => { | |
const rII = getReactInstance( node ); | |
const ownerInstance = rII._currentElement._owner._instance; | |
ownerInstance.props.onPress(); | |
}; | |
var openModal = ( item ) => { | |
const editButton = qsa( item, 'button' ).filter( whereNodeHasClass( 'editButton' ) )[ 0 ]; | |
press( editButton ); | |
}; | |
var selectPosterTab = () => document.querySelector('a.poster-btn').click(); | |
var selectArtwork = () => { | |
const artList = document.querySelector('.artwork-options-list'); | |
const art = artList && artList.querySelector('a.artwork-option'); | |
art && art.click(); | |
return ! ! art; | |
}; | |
var save = () => document.querySelector('.save-btn').click(); | |
var cancel = () => document.querySelector('.cancel-btn').click(); | |
var execute = fn => () => new Promise( resolve => { | |
try { | |
fn(); | |
resolve(); | |
} catch(e) { reject( e ); } | |
}); | |
var wait = delay => () => new Promise( resolve => setTimeout( resolve, delay ) ); | |
var waitFor = selector => () => { | |
const test = () => document.querySelector( selector ) !== null; | |
return new Promise( ( resolve, reject ) => { | |
// Nothing should take more than 5 seconds (I hope) | |
const rejectionTimeout = setTimeout( reject, 5000 ); | |
const pollID = setInterval( () => { | |
if ( test() ) { | |
clearInterval( pollID ); | |
clearTimeout( rejectionTimeout ); | |
resolve(); | |
} | |
}, 17 ); | |
} ); | |
}; | |
var log = msg => () => console.log( msg ); | |
// Main Logic | |
var scroller = qsa( document, 'div' ).filter( whereNodeHasClass( 'MetadataListPageContent-metadataListScroller' ) )[0]; | |
var scrollTop = scroller.scrollTop; | |
var getVisibleItems = () => [ ...scroller.children[0].children ]; | |
var runInSequence = arrOfPromises => arrOfPromises | |
.reduce(( lastStep, nextStep ) => lastStep.then( () => nextStep() ), Promise.resolve() ); | |
var getAmountToScroll = () => { | |
const { min, max } = getVisibleItems().reduce(( minMax, item ) => { | |
const boundingRect = item.getBoundingClientRect(); | |
return { | |
min: Math.min( boundingRect.top, minMax.min ), | |
max: Math.max( boundingRect.bottom, minMax.max ), | |
}; | |
}, { | |
min: Infinity, | |
max: -Infinity, | |
}); | |
return max - min - 200; // -200 to avoid skipping items | |
}; | |
let run = true; | |
var populateArt = () => { | |
if ( ! run ) { | |
console.log('Processing Cancelled'); | |
return; | |
} | |
const visibleItems = getVisibleItems(); | |
const artlessItems = visibleItems.filter( needsArt ); | |
var process = item => Promise.resolve( openModal( item ) ) | |
.then( log( 'Modal open' ) ) | |
.then( waitFor( 'a.poster-btn' ) ) | |
.then( log( 'Modal Ready' ) ) | |
.then( wait( 1000 ) ) | |
.then( selectPosterTab ) | |
.then( log( 'Selected "Poster" tab' ) ) | |
.then( wait( 200 ) ) | |
.then( () => { | |
var hasPosters = selectArtwork(); | |
console.log( hasPosters ); | |
if ( hasPosters ) { | |
return Promise.resolve() | |
.then( log( 'Artwork Selected' ) ) | |
.then( wait( 1500 ) ) | |
.then( save ) | |
.then( log( 'Artwork saved!' ) ); | |
} | |
return Promise.resolve() | |
.then( cancel ) | |
.then( log( 'No artwork available' ) ); | |
} ) | |
.then( wait( 1000 ) ) | |
.catch( err => console.error( err ) ); | |
// return runInSequence( artlessItems.map( item => () => process( item ) ) ) | |
const fnsReturningPromises = artlessItems.map( item => () => process( item ) ); | |
return runInSequence( fnsReturningPromises ) | |
.then(() => scroller.scrollTop += getAmountToScroll()) | |
.then( wait( 1000 ) ) | |
.then( populateArt ); | |
}; | |
return { | |
start: () => { | |
run = true; | |
populateArt(); | |
}, | |
runOne: () => { | |
run = true; | |
populateArt(); | |
run = false; | |
}, | |
stop: () => { | |
run = false; | |
}, | |
}; | |
})(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Run in console with a TV show season open to add an input | |
* which can be used to specify a custom title. | |
*/ | |
(() => { | |
const row = document.createElement('div'); | |
row.classList.add('row'); | |
row.innerHTML = ` | |
<div class="col-md-12"> | |
<div class="form-group selectize-group"> | |
<label for="season-title">Season Title</label> | |
<div class="input-group"> | |
<input class="form-control" id="season-title" name="title" placeholder="Season Title"> | |
</div> | |
</div> | |
</div> | |
`; | |
$('.edit-metadata-form').prepend(row); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment