Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

make pattern block optional

add $YOUTUBE_ACCEPT test
  • Loading branch information...
commit 234fc8d74eb7f8169d05dad9a902ec48eebc6910 1 parent f6fc151
@chocolateboy authored
View
2  README.md
@@ -21,7 +21,7 @@ To upgrade to a new version of the plugin, simply replace the old jar file with
# Tips <a name="Tips"></a>
-* To work around the PMS [bug](http://code.google.com/p/ps3mediaserver/issues/detail?id=759) that causes web video playback to be delayed for ~40s, uncheck "HTTP Engine V2" in the PMS "General Configuration" tab. This can also be done by setting `http_engine_v2 = false` in PMS.conf. Then restart PMS.<sup>[<a href="#HTTPEngine">1</a>]</sup>
+* To work around the PMS [bug](http://code.google.com/p/ps3mediaserver/issues/detail?id=759) that causes web video playback to be delayed for ~40s, uncheck "HTTP Engine V2" in the PMS "General Configuration" tab. This can also be done by setting `http_engine_v2 = false` in PMS.conf. Then restart PMS. See [below](#HTTPEngine) for caveats.
# Troubleshooting <a name="Troubleshooting"></a>
View
8 TODO.groovy
@@ -1,4 +1,4 @@
-/* add mencoder.feature.level (bool) to stash based on MEncoder version */
+/* add $mencoder_feature_level (bool) to stash based on MEncoder version */
/* XPath scraping? */
@@ -9,8 +9,8 @@
format: 'html' // default if xpath is defined
)
-/* add tests for $YOUTUBE_ACCEPT */
-
/* make scripts hot-swappable */
-/* wrap profiles in a try/catch block? */
+/*
+ wrap profile/config evaluation in try/catch blocks so that errors can be recovered from
+*/
View
155 scripts/pmsencoder.groovy
@@ -1,155 +0,0 @@
-config {
- def nbcores = $PMS.getConfiguration().getNumberOfCpuCores()
-
- // the default MEncoder args - these can be redefined in a script
- $DEFAULT_MENCODER_ARGS = [
- '-prefer-ipv4',
- '-oac', 'lavc',
- '-of', 'lavf',
- '-lavfopts', 'format=dvd',
- '-ovc', 'lavc',
- '-lavcopts', "vcodec=mpeg2video:vbitrate=4096:threads=${nbcores}:acodec=ac3:abitrate=128",
- '-ofps', '25',
- '-cache', '16384', // default cache size; default minimum percentage is 20%
- '-vf', 'harddup'
- ]
-
- /*
- this is the default list of YouTube format/resolution IDs we should accept/select - in descending
- order of preference.
-
- it can be modified globally (in a script) to add/remove a format, or can be overridden on
- a per-video basis by supplying a new list to the youtube method (see below) e.g.
-
- exclude '1080p':
-
- youtube $YOUTUBE_ACCEPT - [ 37 ]
-
- add '2304p':
-
- youtube [ 38 ] + $YOUTUBE_ACCEPT
-
- For the full list of formats, see: https://secure.wikimedia.org/wikipedia/en/wiki/YouTube#Quality_and_codecs
- */
-
- $YOUTUBE_ACCEPT = [
- 37, // 1080p
- 22, // 720p
- 35, // 480p
- 34, // 360p
- 18, // Medium
- 5 // 240p
- ]
-
- /*
- this is placed here (i.e. first) as a convenience so that scripts can create/override
- settings common to all other profiles without modifying $DEFAULT_MENCODER_ARGS e.g.
-
- // set the default audio bitrate to 348 Kbps (see default_profile.groovy test)
- profile ('Default') {
- pattern { match { true } }
- action {
- tr '-lavcopts': [ 'abitrate=\\d+': 'abitrate=384' ]
- }
- }
- */
-
- profile ('Default') {
- pattern { match { println("pmsencoder.conf Default"); false } }
- action { }
- }
-
- profile ('YouTube') {
- // extract the resource's video_id from the URI of the standard YouTube page
- pattern {
- match $URI: '^http://(?:\\w+\\.)?youtube\\.com/watch\\?v=(?<youtube_video_id>[^&]+)'
- }
-
- action {
- // fix the URI to bypass age verification
- $URI = "${$URI}&has_verified=1"
-
- // extract the resource's sekrit identifier ($t) from the HTML
- scrape '&t=(?<youtube_t>[^&]+)'
-
- // extract the uploader ("author") so that scripts can use it
- scrape '\\.author=(?<youtube_author>[^&]+)'
-
- // Now, with $video_id and $t defined, call the custom YouTube handler.
- // Note: the parentheses are required for a no-arg action
- youtube()
- }
- }
-
- profile ('Apple Trailers') {
- pattern {
- match $URI: '^http://(?:(?:movies|www|trailers)\\.)?apple\\.com/.+$'
- }
-
- // FIXME: 4096 is a needlessly high video bitrate; they typically weigh in at ~1200 Kbps
- action {
- set '-ofps': '24', '-user-agent': 'QuickTime/7.6.2'
- }
- }
-
- profile ('Apple Trailers HD') {
- pattern {
- match { 'Apple Trailers' in $MATCHES }
- match $URI: '(_h720p\\.mov|\\.m4v)$'
- }
-
- action {
- tr '-lavcopts': [ '4096': '5086' ] // increase the bitrate
- }
- }
-
- profile ('TED') {
- pattern {
- match $URI: '^http://feedproxy\\.google\\.com/~r/TEDTalks_video\\b'
- }
-
- action {
- set '-ofps': '24'
- }
- }
-
- profile ('GameTrailers (Revert PMS Workaround)') {
- /*
- convert:
-
- http://www.gametrailers.com/download/48298/t_ufc09u_educate_int_gt.flv
-
- to:
-
- http://www.gametrailers.com/player/48298.html
- */
-
- // 1) extract the page ID
- pattern {
- match $URI: '^http://(www\\.)?gametrailers\\.com/download/(?<gametrailers_page_id>\\d+)/[^.]+\\.flv$'
- }
-
- // 2) and use it to restore the correct webpage URI
- action {
- let $URI: "http://www.gametrailers.com/player/${gametrailers_page_id}.html"
- }
- }
-
- profile ('GameTrailers') {
- pattern {
- match $URI: '^http://(www\\.)?gametrailers\\.com/'
- }
-
- action {
- /*
- The order is important here! Make sure we scrape the variables before we set the URI.
- extract some values from the HTML
- */
- scrape '\\bmov_game_id\\s*=\\s*(?<gametrailers_movie_id>\\d+)'
- scrape '\\bhttp://www\\.gametrailers\\.com/download/\\d+/(?<gametrailers_filename>t_[^.]+)\\.wmv\\b'
-
- // now use them to rewrite the URI
- $URI = "http://trailers-ak.gametrailers.com/gt_vault/$gametrailers_movie_id/${gametrailers_filename}.flv"
- }
- }
-}
View
1  scripts/pmsencoder.groovy
View
38 src/main/groovy/com/chocolatey/pmsencoder/PMSEncoder.groovy
@@ -222,7 +222,7 @@ class Profile extends Logger {
@Typed(TypePolicy.MIXED) // Groovy++ doesn't support delegation
void extractBlocks(Closure closure) {
- def delegate = new CompileTimeProfileDelegate(config, name)
+ def delegate = new ValidatingProfileDelegate(config, name)
// wrapper method: runs the closure then validates the result, raising an exception if anything is amiss
delegate.runProfileBlock(closure)
@@ -236,20 +236,26 @@ class Profile extends Logger {
// clean (cf. Ruby's BlankSlate)
@Typed(TypePolicy.MIXED) // Groovy++ doesn't support delegation
boolean runPatternBlock(Pattern delegate) {
- // pattern methods short-circuit matching on failure by throwing a MatchFailureException,
- // so we need to wrap this in a try/catch block
+ if (patternBlock == null) {
+ // unconditionally match
+ log.debug("no pattern block supplied: matched OK")
+ } else {
+ // pattern methods short-circuit matching on failure by throwing a MatchFailureException,
+ // so we need to wrap this in a try/catch block
+
+ try {
+ delegate.with(patternBlock)
+ } catch (MatchFailureException e) {
+ log.debug("pattern block: caught match exception")
+ // one of the match methods failed, so the whole block failed
+ return false
+ }
- try {
- delegate.with(patternBlock)
- } catch (MatchFailureException e) {
- log.debug("pattern block: caught match exception")
- // one of the match methods failed, so the whole block failed
- return false
+ // success simply means "no match failure exception was thrown" - this also handles cases where the
+ // pattern block is empty
+ log.debug("pattern block: matched OK")
}
- // success simply means "no match failure exception was thrown" - this also handles cases where the
- // pattern block is empty.
- log.debug("pattern block: matched OK")
return true
}
@@ -383,12 +389,12 @@ public class CommandDelegate extends ConfigDelegate {
}
}
-class CompileTimeProfileDelegate extends ConfigDelegate {
+class ValidatingProfileDelegate extends ConfigDelegate {
public Closure patternBlock = null
public Closure actionBlock = null
public String name
- CompileTimeProfileDelegate(Config config, String name) {
+ ValidatingProfileDelegate(Config config, String name) {
super(config)
this.name = name
}
@@ -416,9 +422,7 @@ class CompileTimeProfileDelegate extends ConfigDelegate {
private runProfileBlock(Closure closure) throws PMSEncoderException {
this.with(closure)
- if (patternBlock == null) {
- throw new PMSEncoderException("invalid profile ($name): no pattern block defined")
- }
+ // the pattern block is optional; if not supplied, the profile always matches
if (actionBlock == null) {
throw new PMSEncoderException("invalid profile ($name): no action block defined")
View
18 src/main/resources/pmsencoder.groovy
@@ -56,17 +56,17 @@ config {
]
/*
- this is placed here (i.e. first) as a convenience so that scripts can create/override
- settings common to all other profiles without modifying $DEFAULT_MENCODER_ARGS e.g.
+ this is placed here (i.e. first) as a convenience so that scripts can create/override
+ settings common to all other profiles without modifying $DEFAULT_MENCODER_ARGS e.g.:
- set the default audio bitrate to 348 Kbps (see the src/test/resources/profile_default.groovy test):
+ // set the default audio bitrate to 348 Kbps
+ // (see src/test/resources/profile_default.groovy)
- profile ('Default') {
- pattern { match { true } }
- action {
- tr '-lavcopts': [ 'abitrate=\\d+': 'abitrate=384' ]
- }
- }
+ profile ('Default') {
+ action {
+ tr '-lavcopts': [ 'abitrate=\\d+': 'abitrate=384' ]
+ }
+ }
*/
profile ('Default') {
View
22 src/test/groovy/MatcherTest.groovy
@@ -54,11 +54,11 @@ class MatcherTest extends PMSEncoderTestCase {
/*
lavcopts look like this:
-
+
-lavcopts vcodec=mpeg2video:vbitrate=4096:threads=2:acodec=ac3:abitrate=128
but for the purposes of this test, this will suffice:
-
+
-lavcopts vbitrate=4096
*/
@@ -77,11 +77,25 @@ class MatcherTest extends PMSEncoderTestCase {
the highest available resolution.
*/
void testYouTube() {
+ youTubeCommon('35')
+ }
+
+ // verify that globally modifying $YOUTUBE_ACCEPT works
+ void testYOUTUBE_ACCEPT() {
+ def customConfig = this.getClass().getResource('/youtube_accept.groovy')
+ youTubeCommon('34', customConfig)
+ }
+
+ private void youTubeCommon(String fmt, URL customConfig = null) {
def youtube = 'http://www.youtube.com'
def uri = "$youtube/watch?v=_OBlgSz8sSM"
def fixedURI = "$uri&has_verified=1".toString()
def command = new Command([ '$URI': uri ])
+ if (customConfig != null) {
+ matcher.load(customConfig)
+ }
+
// bypass Groovy's annoyingly loose definition of true
assertSame(true, matcher.match(command, false)) // false: don't use default MEncoder args
@@ -105,9 +119,9 @@ class MatcherTest extends PMSEncoderTestCase {
// the mysterious $t token changes frequently, but always seems to end in a URL-encoded "="
assert t ==~ /.*%3D$/
assertEquals('HDCYT', stash['youtube_author'])
- assertEquals('35', stash['youtube_fmt'])
+ assertEquals(fmt, stash['youtube_fmt'])
assertEquals(fixedURI, stash['youtube_uri'])
- def wantURI = "$youtube/get_video?fmt=35&video_id=$video_id&t=$t&asv="
+ def wantURI = "${youtube}/get_video?fmt=${fmt}&video_id=${video_id}&t=${t}&asv="
assertEquals(wantURI, stash['$URI'])
assertEquals([], args)
}
View
3  src/test/resources/profile_default.groovy
@@ -1,7 +1,6 @@
config {
profile ('Default') {
- pattern { match { true } }
-
+ // note: the pattern block is (now) optional
action {
tr '-lavcopts': [ 'abitrate=\\d+': 'abitrate=384' ]
}
View
3  src/test/resources/youtube_accept.groovy
@@ -0,0 +1,3 @@
+config {
+ $YOUTUBE_ACCEPT -= [ 35 ]
+}
Please sign in to comment.
Something went wrong with that request. Please try again.