2012-07-28 06:21:30 -04:00
|
|
|
|
|
|
|
import static net.sourceforge.filebot.WebServices.*
|
|
|
|
|
2012-07-30 08:05:18 -04:00
|
|
|
import groovy.xml.*
|
|
|
|
import net.sourceforge.filebot.mediainfo.*
|
|
|
|
|
|
|
|
|
2012-07-28 06:21:30 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* XBMC helper functions
|
|
|
|
*/
|
2012-04-29 01:28:38 -04:00
|
|
|
def invokeScanVideoLibrary(host, port = 9090) {
|
2012-07-30 08:05:18 -04:00
|
|
|
_guarded {
|
2012-05-07 21:16:18 -04:00
|
|
|
telnet(host, port) { writer, reader ->
|
2012-04-29 01:28:38 -04:00
|
|
|
writer.println('{"id":1,"method":"VideoLibrary.Scan","params":[],"jsonrpc":"2.0"}') // API call for latest XBMC release
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-28 06:21:30 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Plex helpers
|
|
|
|
*/
|
|
|
|
def refreshPlexLibrary(server, port = 32400, files = null) {
|
2012-07-30 08:05:18 -04:00
|
|
|
_guarded {
|
2012-07-28 06:21:30 -04:00
|
|
|
def sections = new URL("http://$server:$port/plex").getXml()
|
|
|
|
def locations = sections.Directory.Location.collect{ [path:it.'@path', key:it.parent().'@key'] }
|
|
|
|
|
|
|
|
// limit refresh locations
|
|
|
|
if (files != null) {
|
|
|
|
locations = locations.findAll{ loc -> files.find{ it.path; it.path.startsWith(loc.path) }}
|
|
|
|
}
|
|
|
|
|
|
|
|
locations*.key.unique().each{ key ->
|
|
|
|
new URL("http://$server:$port/library/sections/$key/refresh/").get()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* TheTVDB artwork/nfo helpers
|
|
|
|
*/
|
2012-04-29 01:28:38 -04:00
|
|
|
def fetchSeriesBanner(outputFile, series, bannerType, bannerType2, season, locale) {
|
|
|
|
// select and fetch banner
|
|
|
|
def banner = [locale, null].findResult { TheTVDB.getBanner(series, [BannerType:bannerType, BannerType2:bannerType2, Season:season, Language:it]) }
|
|
|
|
if (banner == null) {
|
|
|
|
println "Banner not found: $outputFile / $bannerType:$bannerType2"
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
println "Fetching $outputFile => $banner"
|
|
|
|
return banner.url.saveAs(outputFile)
|
|
|
|
}
|
|
|
|
|
2012-07-28 06:21:30 -04:00
|
|
|
def fetchSeriesFanart(outputFile, series, type, season, locale) {
|
|
|
|
def fanart = [locale, null].findResult{ lang -> FanartTV.getSeriesArtwork(series.seriesId).find{ type == it.type && (season == null || season == it.season) && (lang == null || lang == it.language) }}
|
|
|
|
if (fanart == null) {
|
|
|
|
println "Fanart not found: $outputFile / $type"
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
println "Fetching $outputFile => $fanart"
|
|
|
|
return fanart.url.saveAs(outputFile)
|
|
|
|
}
|
|
|
|
|
2012-04-29 01:28:38 -04:00
|
|
|
def fetchSeriesNfo(outputFile, series, locale) {
|
|
|
|
def info = TheTVDB.getSeriesInfo(series, locale)
|
2012-07-30 12:59:09 -04:00
|
|
|
info.applyXml('''<tvshow xmlns:gsp='http://groovy.codehaus.org/2005/gsp'>
|
2012-04-29 01:28:38 -04:00
|
|
|
<title>$name</title>
|
2012-07-31 03:46:33 -04:00
|
|
|
<sorttitle>${[name, firstAired as String].findAll{ !it.empty }.join(/ :: /)}</sorttitle>
|
2012-04-29 01:28:38 -04:00
|
|
|
<year>$firstAired.year</year>
|
|
|
|
<rating>$rating</rating>
|
|
|
|
<votes>$ratingCount</votes>
|
|
|
|
<plot>$overview</plot>
|
|
|
|
<runtime>$runtime</runtime>
|
|
|
|
<mpaa>$contentRating</mpaa>
|
|
|
|
<id>$id</id>
|
|
|
|
<episodeguide><url cache="${id}.xml">http://www.thetvdb.com/api/1D62F2F90030C444/series/${id}/all/''' + locale.language + '''.zip</url></episodeguide>
|
|
|
|
<genre>${!genres.empty ? genres[0] : ''}</genre>
|
|
|
|
<thumb>$bannerUrl</thumb>
|
|
|
|
<premiered>$firstAired</premiered>
|
|
|
|
<status>$status</status>
|
|
|
|
<studio>$network</studio>
|
|
|
|
<gsp:scriptlet> actors.each { </gsp:scriptlet>
|
|
|
|
<actor>
|
|
|
|
<name>$it</name>
|
|
|
|
</actor>
|
|
|
|
<gsp:scriptlet> } </gsp:scriptlet>
|
|
|
|
</tvshow>
|
|
|
|
''')
|
|
|
|
.replaceAll(/\t|\r|\n/, '') // xbmc can't handle leading/trailing whitespace properly
|
|
|
|
.saveAs(outputFile)
|
|
|
|
}
|
|
|
|
|
|
|
|
def fetchSeriesArtworkAndNfo(seriesDir, seasonDir, series, season, locale = _args.locale) {
|
2012-07-30 08:05:18 -04:00
|
|
|
_guarded {
|
2012-04-29 01:28:38 -04:00
|
|
|
// fetch nfo
|
|
|
|
fetchSeriesNfo(seriesDir['tvshow.nfo'], series, locale)
|
|
|
|
|
|
|
|
// fetch series banner, fanart, posters, etc
|
2012-07-30 04:39:48 -04:00
|
|
|
["680x1000", null].findResult{ fetchSeriesBanner(seriesDir['poster.jpg'], series, "poster", it, null, locale) }
|
2012-04-29 01:28:38 -04:00
|
|
|
["graphical", null].findResult{ fetchSeriesBanner(seriesDir['banner.jpg'], series, "series", it, null, locale) }
|
|
|
|
|
|
|
|
// fetch highest resolution fanart
|
|
|
|
["1920x1080", "1280x720", null].findResult{ fetchSeriesBanner(seriesDir["fanart.jpg"], series, "fanart", it, null, locale) }
|
|
|
|
|
|
|
|
// fetch season banners
|
|
|
|
if (seasonDir != seriesDir) {
|
2012-07-30 04:39:48 -04:00
|
|
|
fetchSeriesBanner(seasonDir["poster.jpg"], series, "season", "season", season, locale)
|
2012-04-29 01:28:38 -04:00
|
|
|
fetchSeriesBanner(seasonDir["banner.jpg"], series, "season", "seasonwide", season, locale)
|
|
|
|
}
|
2012-07-28 06:21:30 -04:00
|
|
|
|
|
|
|
// fetch fanart
|
|
|
|
fetchSeriesFanart(seriesDir['clearart.png'], series, 'clearart', null, locale)
|
2012-07-30 04:39:48 -04:00
|
|
|
fetchSeriesFanart(seriesDir['logo.png'], series, 'clearlogo', null, locale)
|
|
|
|
fetchSeriesFanart(seriesDir['landscape.jpg'], series, 'tvthumb', null, locale)
|
2012-07-28 06:21:30 -04:00
|
|
|
|
|
|
|
// fetch season fanart
|
|
|
|
if (seasonDir != seriesDir) {
|
2012-07-30 04:39:48 -04:00
|
|
|
fetchSeriesFanart(seasonDir['landscape.jpg'], series, 'seasonthumb', season, locale)
|
2012-07-28 06:21:30 -04:00
|
|
|
}
|
2012-04-29 01:28:38 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-07-28 06:21:30 -04:00
|
|
|
/**
|
|
|
|
* TheMovieDB artwork/nfo helpers
|
|
|
|
*/
|
2012-07-24 13:44:54 -04:00
|
|
|
def fetchMovieArtwork(outputFile, movieInfo, category, language) {
|
2012-04-29 01:28:38 -04:00
|
|
|
// select and fetch artwork
|
2012-07-24 13:44:54 -04:00
|
|
|
def artwork = TheMovieDB.getArtwork(movieInfo.id as String)
|
|
|
|
def selection = [language, 'en', null].findResult{ l -> artwork.find{ (l == it.language || l == null) && it.category == category } }
|
|
|
|
if (selection == null) {
|
2012-04-29 01:28:38 -04:00
|
|
|
println "Artwork not found: $outputFile"
|
|
|
|
return null
|
|
|
|
}
|
2012-07-24 13:44:54 -04:00
|
|
|
println "Fetching $outputFile => $selection"
|
|
|
|
return selection.url.saveAs(outputFile)
|
2012-04-29 01:28:38 -04:00
|
|
|
}
|
|
|
|
|
2012-07-28 06:21:30 -04:00
|
|
|
def fetchMovieFanart(outputFile, movieInfo, type, diskType, locale) {
|
|
|
|
def fanart = [locale, null].findResult{ lang -> FanartTV.getMovieArtwork(movieInfo.id).find{ type == it.type && (diskType == null || diskType == it.diskType) && (lang == null || lang == it.language) }}
|
|
|
|
if (fanart == null) {
|
|
|
|
println "Fanart not found: $outputFile / $type"
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
println "Fetching $outputFile => $fanart"
|
|
|
|
return fanart.url.saveAs(outputFile)
|
|
|
|
}
|
|
|
|
|
2012-07-30 08:05:18 -04:00
|
|
|
def createFileInfoXml(file) {
|
|
|
|
_guarded {
|
|
|
|
def mi = MediaInfo.snapshot(file)
|
|
|
|
def out = new StringWriter()
|
|
|
|
def xml = new MarkupBuilder(out)
|
|
|
|
xml.fileinfo() {
|
|
|
|
streamdetails() {
|
|
|
|
mi.each { kind, streams ->
|
|
|
|
def section = kind.toString().toLowerCase()
|
|
|
|
streams.each { s ->
|
|
|
|
if (section == 'video') {
|
|
|
|
video() {
|
|
|
|
codec((s.'Encoded_Library/Name' ?: s.'CodecID/Hint' ?: s.'Format').replaceAll(/[ ].+/, '').trim())
|
|
|
|
aspect(s.'DisplayAspectRatio')
|
|
|
|
width(s.'Width')
|
|
|
|
height(s.'Height')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (section == 'audio') {
|
|
|
|
audio() {
|
|
|
|
codec((s.'CodecID/Hint' ?: s.'Format').replaceAll(/\p{Punct}/, '').trim())
|
|
|
|
language(s.'Language/String3')
|
|
|
|
channels(s.'Channel(s)')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (section == 'text') {
|
|
|
|
subtitle() {
|
|
|
|
language(s.'Language/String3')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return out.toString()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
def fetchMovieNfo(outputFile, movieInfo, movieFile) {
|
2012-07-30 12:59:09 -04:00
|
|
|
movieInfo.applyXml('''<movie xmlns:gsp='http://groovy.codehaus.org/2005/gsp'>
|
2012-04-29 01:28:38 -04:00
|
|
|
<title>$name</title>
|
2012-07-28 06:21:30 -04:00
|
|
|
<originaltitle>$originalName</originaltitle>
|
2012-07-31 03:46:33 -04:00
|
|
|
<sorttitle>${[collection, name, released as String].findAll{ !it.empty }.join(/ :: /)}</sorttitle>
|
2012-07-28 06:21:30 -04:00
|
|
|
<set>$collection</set>
|
2012-04-29 01:28:38 -04:00
|
|
|
<year>$released.year</year>
|
|
|
|
<rating>$rating</rating>
|
|
|
|
<votes>$votes</votes>
|
2012-07-28 06:21:30 -04:00
|
|
|
<mpaa>$certification</mpaa>
|
|
|
|
<id>tt${imdbId.pad(7)}</id>
|
2012-04-29 01:28:38 -04:00
|
|
|
<plot>$overview</plot>
|
2012-07-28 06:21:30 -04:00
|
|
|
<tagline>$tagline</tagline>
|
2012-04-29 01:28:38 -04:00
|
|
|
<runtime>$runtime</runtime>
|
|
|
|
<genre>${!genres.empty ? genres[0] : ''}</genre>
|
2012-07-28 06:21:30 -04:00
|
|
|
<director>$director</director>
|
|
|
|
<gsp:scriptlet> cast.each { </gsp:scriptlet>
|
|
|
|
<actor>
|
|
|
|
<name>${it?.name}</name>
|
|
|
|
<role>${it?.character}</role>
|
|
|
|
</actor>
|
|
|
|
<gsp:scriptlet> } </gsp:scriptlet>
|
2012-07-31 03:46:33 -04:00
|
|
|
''' + ((movieFile != null ? createFileInfoXml(movieFile) : null) ?: '') + '''
|
2012-07-30 08:05:18 -04:00
|
|
|
<imdb id='tt${imdbId.pad(7)}'>http://www.imdb.com/title/tt${imdbId.pad(7)}/</imdb>
|
|
|
|
<tmdb id='$id'>http://www.themoviedb.org/movie/$id</tmdb>
|
2012-04-29 01:28:38 -04:00
|
|
|
</movie>
|
|
|
|
''')
|
|
|
|
.replaceAll(/\t|\r|\n/, '') // xbmc can't handle leading/trailing whitespace properly
|
|
|
|
.saveAs(outputFile)
|
|
|
|
}
|
|
|
|
|
2012-07-30 08:05:18 -04:00
|
|
|
def fetchMovieArtworkAndNfo(movieDir, movie, movieFile = null, locale = _args.locale) {
|
|
|
|
_guarded {
|
2012-04-29 01:28:38 -04:00
|
|
|
def movieInfo = TheMovieDB.getMovieInfo(movie, locale)
|
2012-07-24 13:44:54 -04:00
|
|
|
|
2012-04-29 01:28:38 -04:00
|
|
|
// fetch nfo
|
2012-07-30 08:05:18 -04:00
|
|
|
fetchMovieNfo(movieDir['movie.nfo'], movieInfo, movieFile)
|
2012-04-29 01:28:38 -04:00
|
|
|
|
|
|
|
// fetch series banner, fanart, posters, etc
|
2012-07-30 04:39:48 -04:00
|
|
|
fetchMovieArtwork(movieDir['poster.jpg'], movieInfo, 'posters', locale.language)
|
|
|
|
fetchMovieArtwork(movieDir['fanart.jpg'], movieInfo, 'backdrops', locale.language)
|
2012-07-28 06:21:30 -04:00
|
|
|
|
2012-07-30 04:39:48 -04:00
|
|
|
fetchMovieFanart(movieDir['clearart.png'], movieInfo, 'movieart', null, locale)
|
2012-07-28 06:21:30 -04:00
|
|
|
fetchMovieFanart(movieDir['logo.png'], movieInfo, 'movielogo', null, locale)
|
|
|
|
['bluray', 'dvd', null].findResult { diskType -> fetchMovieFanart(movieDir['disc.png'], movieInfo, 'moviedisc', diskType, locale) }
|
2012-04-29 01:28:38 -04:00
|
|
|
}
|
|
|
|
}
|