Scripting
This is the place to share your import and playlist scripts. Try to not paste in code, rather upload complete scripts. Also provide a short description and a screenshot, showing how your script organizes the content.
File System Structured Import Script
If you want your videos displayed as they are structured in your file system, like in the following Example:
Movies--+-Movie1
+-Movie2
TVShows-+-TVShow1
+-TVShow2
etc..
Modify your import.js as follows:
Replace:
function addVideo(obj) { var chain = new Array('Video'); addCdsObject(obj, createContainerChain(chain)); }
With:
function addVideo(obj) { var chain, show, season; var location = obj.location.split('/'); chain = new Array(); chain.push(location[location.length-3]); //genre name (Movies, TVShows, etc) chain.push(location[location.length-2]); //series/movie name (Movie1, TVShow1,) addCdsObject(obj, createContainerChain(chain)); }
Download the full import.js script.
File Name Structured Import Script
This is how you can organise your videos into folders that correspond to the first letter of the file name. It looks like this:
-VIDEO-
--
-ABC-
-ALL-
-DEF-
-GHI-
-JKL-
-MNO-
-PQRS-
-T-
-UVW-
-XYZ-
I've given T its own folder because there seem to be a lot of videos that start with T. Also, every video goes in the -ALL- folder as well as the folder that corresponds to the first letter of its file name.
1. Make a copy of the import.js file so you can go back to it if you make a big mistake. I name mine import.js.original
2. Open the import.js file in your favourite text editor and replace the addVideo function with this:
function addVideo(obj) { // first title data var title = obj.meta[M_TITLE]; if (!title) title = obj.title; // always add to the ALL section var chain = new Array('-VIDEO-', '-ALL-'); addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER); // create a chain that matches the first letter of the file name var c = title.charAt(0); if (c == 'a' || c == 'A' || c == 'b' || c == 'B' || c == 'c' || c == 'C') { chain = new Array('-VIDEO-', '-ABC-'); } else if (c == 'd' || c == 'D' || c == 'e' || c == 'E' || c == 'f' || c == 'F') { chain = new Array('-VIDEO-', '-DEF-'); } else if (c == 'g' || c == 'G' || c == 'h' || c == 'H' || c == 'i' || c == 'I') { chain = new Array('-VIDEO-', '-GHI-'); } else if (c == 'j' || c == 'J' || c == 'k' || c == 'K' || c == 'l' || c == 'L') { chain = new Array('-VIDEO-', '-JKL-'); } else if (c == 'm' || c == 'M' || c == 'n' || c == 'N' || c == 'o' || c == 'O') { chain = new Array('-VIDEO-', '-MNO-'); } else if (c == 'p' || c == 'P' || c == 'q' || c == 'Q' || c == 'r' || c == 'R' || c == 's' || c == 'S') { chain = new Array('-VIDEO-', '-PQRS-'); } else if (c == 't' || c == 'T') { chain = new Array('-VIDEO-', '-T-'); } else if (c == 'u' || c == 'U' || c == 'v' || c == 'V' || c == 'w' || c == 'W') { chain = new Array('-VIDEO-', '-UVW-'); } else if (c == 'x' || c == 'X' || c == 'y' || c == 'Y' || c == 'z' || c == 'Z') { chain = new Array('-VIDEO-', '-XYZ-'); } else { chain = new Array('-VIDEO-', '--'); } // add the video addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER); }
3. Save your modified import.js file
4. Re-import all your video
Wishlist: I'd really like to be able to automatically re-organise the folders depending on the number of items that it contains. For example, if there were lots and lots of videos in the -ABC- folder I would like to break it up into -A-, -B-, -C- automatically. I'd also like to put the number of videos that are contained in the folder in the name of the folder; for example, -ABC (235)-. Unfortunately I don't think this is possible without some big changes to mediatomb.
Parsing Of File Names For TV Shows
This is how you can automagically organize your tv shows in folders that correspond to the name of the show and the season. For turing:
Videos\my_name_is_earl.2x19.harassed_a_reporter.dvdrip_xvid-fov.avi Videos\Heroes.S02E07.Out of Time.HDTV.XviD-LOL.[TvT].avi Videos\house.320.hdtv-lol
to
Videos\TV Shows\My Name Is Earl\Season 02\Episode 19 - Harassed A Reporter Videos\TV Shows\Heroes\Season 02\Episode 07 - Out Of Time Videos\TV Shows\House\Season 03\Episode 20
It looks like this:
Note: Do make a backup of your import script if something went wrong!
Video
TV Shows
My Show That I Like
Season 01
Episode 01 - Things That Matters
Episode 02
Episode 03 - Another Title
Add the following code in the top of the function addVideo in your import script Replace:
if(checkIfSerieAndAdd(obj)) return;
If you are using the original script, the result should look like this:
function addVideo(obj) { if(checkIfSerieAndAdd(obj)) return; var chain = new Array('Video'); addCdsObject(obj, createContainerChain(chain)); }
Now it is time to add the function checkIfSerieAndAdd and the required functions. Add the following code to the end of the file:
function checkIfSerieAndAdd(obj) { var excludeSamples = true; var fixEpisodeNames = true; var patterns = [ /(.*)s(\d\d)e(\d\d)(\D.*)/i|>, /(.*)s(\d\d)(\D)(.*)/i|>, /(\D*)[\.|\-|_](\d)(\d\d)([\.|\-|_]\D.*)/i|>, /(\D*)(\d)[^0-9](\d\d)(\D.*)/i|> ]; for(var i=0;i<patterns.length;i++){ var match = patterns[i].exec(obj.title); if(match){ var name = fixSerieName(match[1]); if(name.length == 0) continue; var season = parseFloat(match[2]); if(season == 0) continue; var episode = parseFloat(match[3]); var leftover = match[4]; var r = new RegExp(); if(excludeSamples && /\Wsample\W/i.test(leftover)) return true; if(episode == 0){ // Some malformed string leftover = obj.title; } var chain = new Array('Video', 'TV Shows'); chain.push(name); var paddedSeason = 'Season ' + padLeft(season, '0', 2); chain.push(paddedSeason); var paddedEpisode = padLeft(episode, '0', 2); if(paddedEpisode == 'NaN') paddedEpisode = ''; else paddedEpisode = ' ' + paddedEpisode; if(fixEpisodeNames){ var commonabbr = [ 'divx', 'xvid', 'dvdrip', 'hdtv', 'lol', 'axxo', 'repack', 'xor', 'pdtv', 'real', 'vtv', 'caph', '2hd', 'proper', 'fqm', 'uncut', 'topaz', 'tvt', 'notv', 'fpn', 'fov', 'orenji', '0tv', 'omicron', 'dsr', 'ws', 'sys', 'crimson', 'wat', 'hiqt', 'internal'] for(var j=0;j<commonabbr.length;j++){ var re = new RegExp("[\\W|_]" + commonabbr[j] + "[\\W|_]", 'gi'); leftover = leftover.replace(re, '.'); } while(leftover.indexOf('..')!=-1) leftover = leftover.replace(/\.\./g, '.'); leftover = leftover.replace(/\.\w*$/, ' '); leftover = fixSerieName(leftover); if(leftover.length > 0) leftover = ' - ' + leftover; } obj.title = 'Episode' + paddedEpisode + leftover; addCdsObject(obj, createContainerChain(chain)); return true; } } return false; } function fixSerieName(name){ name = name.replace(/_/g, ' '); name = name.replace(/\./g, ' '); name = name.replace(/ /g, ' '); name = removeStartingDashesAndSpaces(name); name = removeEndingDashesAndSpaces(name); return toProperCase(name); } function removeStartingDashesAndSpaces(name){ if(name.length == 0) return name; while(name.indexOf(' ') == 0 || name.indexOf('-') == 0){ name = name.replace(/^ /g, ''); name = name.replace(/^-/g, ''); } return name; } function removeEndingDashesAndSpaces(name){ if(name.length == 0) return name; while(name.lastIndexOf(' ') == name.length - 1 || name.lastIndexOf('-') == name.length - 1){ name = name.replace(/ $/g, ''); name = name.replace(/-$/g, ''); } return name; } function toProperCase(s) { return s.toLowerCase().replace(/^(.)|\s(.)/g|>, function($1) { return $1.toUpperCase(); }); } function padLeft(str, pad, count) { str += ''; while(str.length < count){ str = pad + str; } return str; }
Save your modified import.js and re-import all your videos.
Importing Tracks From flac+cue CD Image
This allows you to import CD images in flac format with an external cue sheet to your media server. The script assumes that the whole album is contained in one flac encoded file with an accompanying text format cue file describing the track layout in within the file and the meta data for the whole disc and individual tracks. The tracks are imported as “dummy” urls containing only the meta data, the flac file name, and the track location within the file. The urls are then provided through a transcoding script which produces the audio in wav format for the clients.
Changes to config.xml defining some mappings
* <import> → <mappings> → <extension-mimetype> add: <map from=“cue” to=“audio/x-cue”/>
* <import> → <mappings> → <mimetype-contenttype> add: <treat mimetype=“audio/x-cue” as=“playlist”/>
* <transcoding> → <mimetype-profile-mappings> add: <transcode mimetype=“audio/x-cue+flac” using=“flac2raw”/>
* <transcoding> → <profiles> add:
<profile name="flac2raw" enabled="yes" type="external"> <mimetype>audio/x-wav</mimetype> <accept-url>yes</accept-url> <first-resource>yes</first-resource> <accept-ogg-theora>no</accept-ogg-theora> <agent command="flacNcue2wav.sh" arguments="%in %out"/> <buffer size="1048576" chunk-size="131072" fill-size="262144"/> </profile>
Changes to import.js and common.js
To be able to call addAudio() function from playlist.js, it must be transferred from import.js to common.js. Also, the .cue extension must be specified to be a known playlist extension by changing getPlaylistType() function in common.js to be
function getPlaylistType(mimetype) { if (mimetype == 'audio/x-mpegurl') return 'm3u'; if (mimetype == 'audio/x-scpls') return 'pls'; if (mimetype == 'audio/x-cue') return 'cue'; return ''; }
Cue sheet parsing
The majority of the required scripting is done in playlist.js. The cue sheet parser is added to the main function as an own branch in addition to .m3u and .pls handling. After the parser has collected enough information of a track, it calls a new createSubItem() function which creates an object with the correct meta data, assigns type OBJECT_TYPE_ITEM_EXTERNAL_URL to it, and encodes the track location in the url in the form
http://cue2flac/params?skip=1:23.45&until=3:45.67&filename=/absolute/path/to/image.flac
This tells that the track location in disc is the range 1:23.45-3:45.67 in the given file. After all metadata is assigned to the newly created track object, it is added to the data base with addAudio() function (remember, the one transferred from import.js to common.js).
The full playlists.js script.
The transcoding script decoding the url for an external program is given in the transcoding section.
News Feed