Skip to content

Instantly share code, notes, and snippets.

@obfuscode
Created September 11, 2014 14:20
Show Gist options
  • Save obfuscode/22f8d53aba75e8fee6d9 to your computer and use it in GitHub Desktop.
Save obfuscode/22f8d53aba75e8fee6d9 to your computer and use it in GitHub Desktop.
A script that recursively reads a drag-n-dropped folder of movies and retrieves TMDb info and posters for them. See Demo Here: https://www.dropbox.com/s/7mauwell3ribju0/MovieFolderParser.mov?dl=0
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>Movie Folder Parser</title>
<meta name="description" content="" />
<meta name="keywords" content="" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<style>
html, body {
margin: 0;
padding: 0;
font-family: 'Open Sans';
}
#dropArea {
height: 100px;
line-height: 100px;
color: #bbb;
font-size: 18px;
font-weight: bold;
text-align: center;
background-color: #f5f5f5;
border-bottom: 1px solid #ccc;
}
#files {
overflow: auto;
}
.file {
float: left;
display: inline;
position: relative;
margin: 10px;
width: 150px;
height: 260px;
font-size: 10px;
text-align: center;
}
.file img {
display: block;
width: 154px;
border: 1px solid #ccc;
}
.file i {
display: block;
width: 154px;
height: 231px;
line-height: 231px;
text-align: center;
border: 1px solid #ccc;
}
.file i.fa-clock-o {
color: #ccc;
}
.file i.fa-warning {
color: #ffd73f;
}
.file i.fa-times {
color: #ffa6a4;
}
.file i.fa-times:after {
content: "Movie Not Found";
position: absolute;
top: 25px;
left: 0;
width: 100%;
color: #000;
font-size: 12px;
text-align: center;
}
#TMDbNotice {
padding: 5px 10px;
text-align: center;
border: 1px solid #ccc;
background-color: #ffffe6;
}
.poweredBy {
margin: 10px;
font-size: 12px;
text-align: center;
}
</style>
</head>
<body>
<div id="dropArea">Drop Files / Folders Here</div>
<div id="files"><div id="TMDbNotice" style="display:none;"></div></div>
<div class="poweredBy">Powered by <a href="http://www.themoviedb.org">TMDb</a></div>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
<script type="text/javascript" src="_inc/tmdb.js"></script><!-- Get this script at https://github.com/EtienneWan/tmdb-js/ -->
<script type="text/javascript">
var totalFiles = 0;
var fileHandles = [];
var TMDbNumRequestGroups;
var TMDbInterval;
var TMDbCurrentRequest = 1;
function updateQueueLength(quantity) {
totalFiles += quantity;
console.log('Queue now at: '+totalFiles);
}
function enqueueFileAddition(file) {
fileHandles.push(file);
checkQueue();
}
function checkQueue() {
console.log('Checking Queue: '+fileHandles.length+' / '+totalFiles);
// If all the files we expect have shown up, then flush the queue.
if (fileHandles.length === totalFiles) {
console.log('All files read, displaying to user ('+totalFiles+' files)');
displayFiles();
}
}
function loadFiles(files) {
updateQueueLength(files.length);
for (var i = 0; i < files.length; i++) {
var file = files[i];
var entry, reader;
if (file.isFile || file.isDirectory) {
entry = file;
} else if (file.getAsEntry) {
entry = file.getAsEntry();
} else if (file.webkitGetAsEntry) {
entry = file.webkitGetAsEntry();
} else if (typeof file.getAsFile === 'function') {
enqueueFileAddition(file.getAsFile());
continue;
} else if (File && file instanceof File) {
enqueueFileAddition(file);
continue;
} else {
updateQueueLength(-1);
checkQueue();
continue;
}
if (!entry) {
updateQueueLength(-1);
checkQueue();
} else if (entry.isFile) {
entry.file(function(file) {
enqueueFileAddition(file);
}, function(err) {
console.warn(err);
});
} else if (entry.isDirectory) {
reader = entry.createReader();
reader.readEntries(function(entries) {
loadFiles(entries);
updateQueueLength(-1);
checkQueue();
}, function(err) {
console.warn(err);
});
}
}
}
function cleanName(handleIndex) {
var item, itemName, movieName, movieExt, year, yearVal;
item = fileHandles[handleIndex];
itemName = item.name;
movieName = itemName.substr(0, itemName.lastIndexOf('.'));
movieExt = (itemName.substr(itemName.lastIndexOf('.'))).toLowerCase();
year = movieName.match(/\(([1-2][0-9][0-9][0-9])\)/);
yearVal = '';
if(year) {
movieName = (movieName.replace(year[0], '')).trim();
yearVal = year[1];
}
return [movieName, yearVal];
}
function displayFiles() {
var TMDbTime, TMDbTimeMin, TMDbTimeSec, TMDbTimeText;
TMDbNumRequestGroups = Math.ceil(totalFiles / 30);
TMDbTime = (TMDbNumRequestGroups * 11) - 11;
if(TMDbTime > 60) TMDbTimeMin = Math.floor(TMDbTime / 60);
TMDbTimeSec = TMDbTime % 60;
if(TMDbTimeMin > 0 && TMDbTimeSec > 0) TMDbTimeText = TMDbTimeMin+' min '+TMDbTimeSec+' sec';
else if(TMDbTimeMin > 0) TMDbTimeText = TMDbTimeMin+' min';
else if(TMDbTimeSec > 0) TMDbTimeText = TMDbTimeSec+' sec';
if(TMDbTimeText) $('#TMDbNotice').html('Our movie information provider, TMDb, limits how fast we can fetch movie info.<br />Your information will be complete in <strong>roughly '+TMDbTimeText+'</strong>').show();
for(var i=0; i<totalFiles; i++) {
var movieName = (cleanName(i))[0];
$('#files').append('<div id="item'+i+'" class="file"><i class="fa fa-clock-o fa-3x"></i>'+movieName+'</div>');
}
// Start TMDb calls.
if(TMDbNumRequestGroups == 1) {
console.log('Starting TMDb Requests - Single');
sendRequests();
} else {
// TMDb rate limits calls to 30 every 10 sec so we have to do this in an interval
// Setting it at 11 seconds just to be safe.
console.log('Starting TMDb Requests - Multiple ('+TMDbNumRequestGroups+')');
sendRequests();
TMDbInterval = setInterval(function() { sendRequests() }, 11000);
}
}
function sendRequests() {
var startNum = (TMDbCurrentRequest * 30) - 30;
var endNum = TMDbCurrentRequest * 30;
if(endNum > totalFiles) endNum = totalFiles;
console.log('Sending Request Group '+TMDbCurrentRequest+'/'+TMDbNumRequestGroups+' ('+startNum+'-'+endNum+')');
for(var i=startNum; i<endNum; i++) {
var itemInfo = cleanName(i);
var movieName = itemInfo[0];
var yearVal = itemInfo[1];
TMDbCall(i, movieName, yearVal);
}
if(TMDbNumRequestGroups > 1) {
if(TMDbNumRequestGroups == TMDbCurrentRequest) {
clearInterval(TMDbInterval);
console.log('TMDb Request Groups - DONE - Clearing Interval ('+TMDbCurrentRequest+')');
TMDbCurrentRequest = 1;
} else {
TMDbCurrentRequest++;
console.log('TMDb Request Groups - Incrementing Interval ('+TMDbCurrentRequest+')');
}
}
}
function TMDbCall(handleIndex, movieName, yearVal) {
console.log(handleIndex+' Searching for: '+movieName+' '+yearVal);
tmdb.call("/search/movie", {
"query": movieName,
"year": yearVal
},
function(e) {
if(!e.results[0]) $('#item'+handleIndex+' i').removeClass('fa-clock-o').addClass('fa-times');
else {
//console.log(e);
var poster = e.results[0].poster_path;
//var title = e.results[0].original_title;
//var backdrop = e.results[0].backdrop_path;
if(poster) {
$('#item'+handleIndex+' i').remove();
$('#item'+handleIndex).prepend('<img src="'+readCookie('TMDbBaseUrl')+'/w154/'+poster+'" />');
} else {
$('#item'+handleIndex+' i').removeClass('fa-clock-o').addClass('fa-warning');
}
}
},
function(e) {
console.log("Error callback: " + e);
}
);
}
function handleDragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.dataTransfer.dropEffect = 'copy';
}
function createCookie(name, value, days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
function eraseCookie(name) {
createCookie(name,"",-1);
}
$(function() {
var dropZone = document.getElementById('dropArea');
dropZone.addEventListener('dragover', handleDragOver, false);
dropZone.addEventListener('drop', function(e) {
e.stopPropagation();
e.preventDefault();
if (e.dataTransfer && e.dataTransfer.items) {
loadFiles(e.dataTransfer.items);
} else if (e.dataTransfer && e.dataTransfer.files) {
loadFiles(e.dataTransfer.files);
}
});
if(!readCookie('TMDbBaseUrl')) {
tmdb.call("/configuration", {},
function(e) {
createCookie('TMDbBaseUrl', e.images.base_url, 2);
console.log(e);
},
function(e) {
console.log(e);
}
);
}
});
</script>
</body>
</html>
@ThumperDone
Copy link

Problems finding all movies under a 'parent' folder. Each movie is in it's own folder due to some having subtitles. All movies have different naming so none can be found using this script.
Ignore 'Tv', just showing folder structure.

Folders are setup like:
Drive#1/
--------- Movies/
------------------- Free State of Jones [2016]/
------------------------------------------------------ Free.State.of.Jones.2016.HDRip.XviD.AC3-EVO.avi
Drive#2/
--------- Movies/
------------------- X-Men Apocalypse (2016)/
----------------------------------------------------- X-Men.Apocalypse.2016.PROPER.BDRip.x264-Larceny.mkv
--------- Tv/
------------------- Bones/
---------------------------- Season 01/
------------------------------------------- Bones.S11E01.HDTV.x264-FLEET.mkv
------------------------------------------- Bones.S11E02.HDTV.x264-LOL.mkv

Going directly to https://www.themoviedb.org to test file name formats:
search for: Free State of Jones 2016 = Not Found
search for: Free State of Jones [2016] = Not Found
search for: Free State of Jones (2016) = Not Found
but search for: Free State of Jones y:2016 = Found (every movie tested)
or for: Ratchet and Clank 2016 = Not Found
or for: Ratchet and Clank [2016] = Not Found
or for: Ratchet and Clank (2016) = Not Found
but search for: Ratchet and Clank y:2016 = Found

Working example (notice the y: filter): https://www.themoviedb.org/search?query=Free+State+of+Jones+y%3A2016

Question:
Where do I add the '[' & ']' so they are removed along with '(' & ')' so years are searched along with the below filter..
next where to add the 'y:' filter as it appears this one thing made all names able to be found (when year is included).
THEN.. ignore "all" text after the Year so no matter the file name add-ons they are not used in the search!

(the y: filter is preferred as Hollywood is hell bent on reboots with the same titles)

Side note: how to (when script is hosted locally) hard script in a set of top folders (on different smb drives) so it pulls when the page is opened?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment