JW 7.3.0 is now in beta and is reported to include the following feature:

Native HTML5 caption tracks now utilized for iOS devices, allowing for fullscreen subtitles

A lot has changed with JW Player since my previous post regarding it’s lack of support for captions on iOS – including a complete rebuild!

That was back in November 2013 and related to JW Player 6.7.

Over two years on and the latest version of JW Player is 7.2.4, but unfortunately, one thing that still hasn’t changed is it’s ability to provide caption support for media played on iPhones and iPads in fullscreen.

Whilst my original post was useful in demonstrating the principle of how JW Player captions can be enabled for iOS use, it was by no means a complete solution – there are a number of other scenarios/states which need to be handled, and it also does nothing to account for cross-domain/CORS issues or to style the captions as suggested by the JW captions configuration block.

Introducing the JW/iOS captions plugin

Not wanting to leave things half finished, I decided to create a plugin to provide a more robust solution – whilst making it easier to implement.

The JW/iOS captions plugin offers the following features:

  • Overcomes basic cross-domain issues
  • Honours the JW captions block styling configuration
  • Uses native captions on iPhone and iPad in fullscreen.

An example of how to use this plugin can be found at the following page: Enabling JW Player captions on iOS

Tatami for Online Video

If you are using Tatami for Online Video to build and generate your JW Player embeds, this plugin will automatically be included when your player is rendered on iOS.

UPDATE: According to the release notes of JW 7.2.2 (18th December 2015) this should now be fixed: Player should now respond to touch events properly on iOS 7.

Although it was identified during the beta testing phase that JW7 wasn’t working on certain iOS devices (7th July 2015), the code was still pushed into production on 20th July 2015.

Even after a subsequent point release (7.0.1 on 5th August 2015) this situation had still not been resolved and at no point had this been recorded as a known issue – JW7 Release notes

Then on 18th August 2015, the JW Team shared their stance that JW7 actually only currently supports iOS8:

Todd Grunow – Aug 18, 2015 05:12PM EDT

Our document at http://support.jwplayer.com/customer/portal/articles/1403653-browser-device-reference has been updated to indicate that we currently support iOS 8 and up. Our engineers are looking into a fix to enable support in iOS 7. They expect to have a fix in the coming weeks.

Whilst this may appear at odds with the message presented by the marketing arm of JW Player, long time followers of JW operations will know to take most of their claims with a pinch of salt!

A tweet claiming JW7 supports all devices and screens...

Incidentally, JW7 no longer supports IE8 either – a position which has actually been documented.

So what’s the issue?

Depending on the media type you are loading in JW7, you will likely experience the following behaviour on mobile devices running operating systems earlier than iOS8:

  • YouTube media – Tapping on the JW play button causes the icon to switch to a buffering state, whilst behind this the YouTube play button appears. The media won’t actually begin to play until you tap again on the poster image. If you were to initially tap on the poster image (rather than the play button) the media will play first time.
  • Other media – In most cases the player is completely unresponsive. No matter where you click the player will not react.

In both instances the JW play button is incorrectly positioned relative to the middle of the device viewport – rather than appearing in the middle of the player area.

And what’s the workaround?

YouTube media

For JW7 embeds which only use YouTube media, the workaround is relatively straightforward. You basically have to tell JW Player to ignore the initial touch event and (quite literally) pass this event through to the underlying YouTube player. This can be done by adding the following CSS to your page:

#<PLAYERID> .jw-display-icon-container{
    pointer-events:none;
}

Where <PLAYERID> above is replaced with the container ID used in your specific player setup.

Whilst this will make the player react correctly, it doesn’t resolve the issue of the incorrectly positioned play button.

Other media

Unfortunately, for JW7 embeds which use other media, it’s not as straightforward as simply adding some CSS to the page.

Fortunately however, I’ve written a plugin to take care of the additional complexities and so all you need to do is to add the following code to your player setup:

"plugins":{
    "http://www.dev.powered-by-haiku.co.uk/solutions/jw7ios7fix/code/jw7ios7fix.js":{}
}

This plugin works for both YouTube media and other media embeds – and resolves the issue of the incorrectly positioned play button for both scenarios.

Tatami for Online Video

If you are using Tatami for Online Video to build and generate your JW Player embeds, this workaround will automatically be included when your player is rendered using iOS6/iOS7.

NOW AVAILABLE!

The following snapshot has been built to demonstrate just some of the functionality available in Tatami for JW Player

http://dev.powered-by-haiku.co.uk/solutions/tatami/?share=f3xZJaPrmp

Tatami for JW Player is an online configuration tool which allows you to build quite complex JW setups, with common behaviours and actions, using an intuitive drag-n-drop visual interface.

An example of the Tatami for JW Player interface

Tatami provides the means to build modular configurations which can then be used to extend JW player embeds by simply drawing lines and connecting various components.

Additional features

It also includes a “codepen” style sharing facility where one person can build a configuration, snapshot it, and then send it to someone else for review and tweaks, before generating an updated embed code.

Plus:

  • Allows you to decouple the ongoing management of JW player configurations and playlists from the web page they are embedded on
  • Use tatami for end-to-end embedding of JW configurations, or as an easy way to just create Playlists, Listy or Advertising Setups – you have the flexibility to decide how you use it
  • Embed code is completely obfuscated in order to protect your licence key and media URLs from casual “view-sourcers”
  • Embeds can be restricted to only render a player when included on specified domains
  • Copy/paste/clone configuration components – making it quick and easy build and maintain similar setups
  • Add media from YouTube and Soundcloud directly within Tatami
  • Built-in “Mouse trigger” and “Scroll trigger” behaviours for advanced interaction with the player
  • Built-in option to pause all other players on the page as a result of a player event or behaviour
  • Zero-code, event-based video overlays – including countdown to YouTube livestreams

Coming soon

The following features are in the pipeline:

  • Build a Tatami Set by simply pasting your existing JW setup code into Tatami
  • Support for JW Platform & token signed media

 

NOW AVAILABLE!

The following snapshot has been built to demonstrate just some of the functionality available in Tatami for JW Player

http://dev.powered-by-haiku.co.uk/solutions/tatami/?share=f3xZJaPrmp

As of March 4, 2014 the YouTube Data API (v2) was officially deprecated, and in early June 2015 was completely removed – meaning that any JW Player implementation which uses a YouTube playlist for it’s source (in the format shown below) will now fail to load:

  jwplayer("example").setup({

  ...

  "playlist":"http://gdata.youtube.com/feeds/api/playlists/xxxxxxxxxxxxx",

  ...

  }

Now, whilst there are new URL’s available allowing access to YouTube feeds without the need for an API key or oAUTH authentication, these don’t currently work in JW Player due to the feed/media structure not being compatible with JW Player’s expected Media RSS format:

https://www.youtube.com/feeds/videos.xml?playlist_id=PLAYLISTID
https://www.youtube.com/feeds/videos.xml?channel_id=CHANNELID
https://www.youtube.com/feeds/videos.xml?user=USERNAME

Additionally they have restrictive CORS headers and appear to only return the latest 15 videos with no apparent way to page through the full feed…

Ho hum!

Fortunately there is still a way you can make use of YouTube playlists in your JW Player setup.

Tubey is a JW Player plugin which, with a slight tweak to your configuration, will allow you to continue to load the full YouTube playlist. It also provides the ability to merge multiple YouTube playlists into one.

Listy for JW Player is a plugin providing feature rich, customisable playlists which can be saved and loaded between sites.

It provides the capabilities to allow playlists to be manipulated without interrupting play or having to re-initialise the player.

Latest features

  • Tubey integration – Allows multiple YouTube playlists to be initially loaded into the player
  • Add from Soundcloud – Search and add Soundcloud files directly from within the Listy playlist
  • Save / load playlist – A premium feature which will allow your users to register with Listy giving them the ability to save, load and create new playlists. Saved playlists can then be accessed across sites, browsers or devices
  • Export – Use Listy to build your playlists and then export to JSON or RSS at the touch of a button
  • Prefetch – Allowing you to configure Listy to prefetch playlist items which are available via progressive download in order to boost performance when switching between items

Other features include

  • Shuffle – Randomise the remaining playlist, after the current playing item, at the touch of a button
  • Search – Quickly pinpoint the item you are looking for without needing to scroll through a long list
  • Edit – Add, remove and move items around a playlist without interrupting the current playback
  • Preview – Check you’ve got it right before adding an item to the playlist
  • Custom parameters – Add custom parameters to playlist items – which will then be searched against or can be displayed in a custom playlist
  • Add from YouTube – Search and add YouTube videos directly from within the Listy playlist
  • Accessible – Navigate through playlist items using a keyboard only
  • Next / Previous – Navigate through playlist items using the next and previous buttons on the JW Player control bar
  • Multiple skinning – Apply separate skins to each component: the player, the playlist and Listy controls
  • Custom playlist HTML – Complete control over the playlist HTML and the associated styling
  • Custom buttons & labels – All labelling within Listy is configurable – allowing for localisation – and the API (coming soon) will allow you to quickly build custom actions
  • Export – coming soon – Use Listy to build your playlists, then export to inline, RSS or XML at the touch of a button

Documentation

Information on how to setup, configure and use Listy for JW Player can be found here.

About Chiki

Chiki is an accessibility aid for web users who primarily use a keyboard to navigate sites – it’s basically “Skip Links” with attitude!

One of Chiki’s aims is to rationalise the document outline of a web page and present it in a consistent way using a traditional semantic structure – regardless of the underlying code quality or markup used. It also highlights Landmark Areas within the page and provides the means to jump directly to these areas.

When it comes to Page Links, Chiki will remove duplicates from the same Landmark Area whilst standardising the link text across various screen readers.

Additionally, Chiki overcomes issues where JavaScript events bound to a link may prevent the default link behaviour – causing the link to appear unresponsive to a keyboard user – this problem is discussed further in this excellent article: Keyboard-Only Navigation for Improved Accessibility.

Additional benefits of Chiki

  • Allows you to Promote certain Links so they appear first in the tab order.
  • Exposes the page tabbing order for sighted keyboard users who are attempting to navigate without a mouse.
  • Allows you to override the behaviour of Links which are coded to automatically open in a new window.
  • Provides the means to access Footer navigation links which are on “endlessly scrolling” pages.
  • For web site owners, Chiki is a great way to visually sense check the tab order and associated link texts that a keyboard/screen reader user will experience.

Promoted Links

One really useful feature of Chiki is the ability to Promote Links. Using a simple configuration field you are able to specify word combinations which, if found in the text of a Page Link, will promote that link to a special section within the Chiki Link Panel – at the top of the tab order.

This makes it easier to find links that are important to you.

Using Chiki Links

The default action when selecting a Chiki Link will be to focus you at the relevant point within the underlying web page – whether it’s a Landmark Area, Page Heading or Page Link.

In the case of Page Links you can invoke the default link behaviour directly by holding down the shift key when selecting the Chiki Link – thereby overriding any “new window” behaviours and also re-enabling links that are broken due to JavaScript event binding.

Try it yourself

For an example of how a bad accessibility experience can be improved using Chiki, try loading Chiki as a bookmarklet on next.co.uk.

Although Next claim to be working to make the Next site as accessible as possible to be used by everybody the following accessibility issues have been long-standing:

  • Main navigation is unusable with a keyboard due to restrictive jQuery event binding
  • Lack of “skip links” means you have to tab over 82 country links before getting to Customer services, Site map or Accessibility links
  • When you do get to the Customer services or Accessibility links, they will open in a new window without warning

Web users: Loading Chiki as a Bookmarklet

A bookmarklet is simply a bookmark stored on your web browser favourites bar (or in the bookmarks folder) that contains JavaScript to dynamically extend the currently loaded page. You can load Chiki this way by visiting any web page, and after the page has loaded, copy and paste the following code into your browser URL bar and press return:

javascript:(function(){h=document.getElementsByTagName('head')[0];s=document.createElement('script');s.src='//www.dev.powered-by-haiku.co.uk/chiki/chiki.min.js';h.appendChild(s);void 0;})();

NOTE: Ensure the javascript: part is included – Chrome tends to remove it after you paste into the URL bar.


Site owners: Add it to your site

Obviously when loading Chiki as a Bookmarklet it will only exist temporarily for the page it is manually loaded on – when you change page, you will need to reload the Bookmarklet.

The real value of Chiki comes when it is loaded site-wide.

Web site owners can add Chiki to their sites by including a link to the Chiki library in their page <HEAD> for example:

<HEAD>
...
<!-- Chiki library -->
<script src="//www.dev.powered-by-haiku.co.uk/chiki/chiki.min.js"></script>
...
</HEAD>

 

Configuring Chiki

Once the Chiki library has been added in this way, you can customise the colours used, along with the text displayed in the dialog footer and the default terms included in the Promote Links configuration field.

This can be achieved by calling the .customise() method as follows:

<script>
chiki.customise({
    footer_text: "Chiki © Powered By Haiku",
    promote_default: "Accessibility\nSite map",
    dialogBorderColor: "#888",
    dialogFooterTextColor: "#fff",
    dialogBackgroundColor: "#F5F5F8",
    dialogButtonColorOn: "#d14",
    dialogButtonColorOff: "#08c",
    dialogButtonTextColorOn: "#fff",
    dialogButtonTextColorOff: "#fff",
    dialogPromotedLinkBorderColor: "#08c",
    dialogLinkHighlightColor: "#d14"
});
</script>


Chrome users: Adding an extension

By downloading and enabling this Chiki Chrome extension, you can have Chiki automatically load for any web page that you visit.

Enabling the Chiki Chrome extension

  1. Get the Chiki Chrome extension (ZIP) from here
  2. Unzip the file into a directory on your local disk. eg: c:\chiki\
  3. Open the Chrome extensions tab – chrome://extensions/
  4. Check the Developer mode checkbox and then click on the Load unpacked extension... button
  5. From the dialog, select the directory where you have extracted the Chiki Chrome extension

Any comments, thoughts or suggestions regarding Chiki would be welcome. You can contact me @jherrieven on twitter.

Johnny – How to turn off analytics with JW6.7
Ethan – It can be disabled with the enterprise player.

And there it is…

JW Player’s middle finger salute to it’s army of self-hosters, one-man-bands and SME’s – yet another example of where capital investment (and the blinkered demand for ROI) is eroding the trust, belief and ultimately the ongoing relationship between a company and it’s legion of customers – the people who got it into the investable position in the first place.

Whilst there have been a number of questionable “outputs” from the JW Team over the last year, this “analytics” point alone is quite a curious one.

I would encourage Dave Otten and Jeroen W to take a bit more time in trying to understand it.

Since JW6, the majority of people who have been looking to disable analytics wish to do so, not because they don’t actually want analytics (most would probably be indifferent to it), but because they need the player to stop making calls to the JW CDN.

Here’s the rub

When the player renders in an end-user’s browser, and if for any reason it cannot reach the JW CDN, it will fail to produce a working player. Instead the end-user will be confronted with:

"Could not load plugins: File not found"

Now, there have been significant discussion in the JW forums around the logic of actually crippling the player under these circumstances.

And there are legitimate use-cases stated where “free-edition” hosters need to disable analytics – but again, not because they don’t want analytics… but because they want to present videos in JW Player whilst offline/behind a corporate firewall/or simply don’t want to be dependent on availablity of JW’s CDN.

I personally struggle to see the strategic value in this from a marketing point of view – as I’ve previously indicated:

The mad thing about this is:

1) As stated before, the users of the free version are unlikely to actually care about analytics – it’s one instance where a chargeable value add service makes sense.
2) You are effectively crippling peoples ability to evaluate your product with a view to paying for an enhanced version
3) Providing a robust free version that plays everywhere (online) has got to be one of the best mechanisms to advertise and promote your product – given it will clearly have your branding and links to your site.

Indeed, relating to JW6.4, Jeroen acknowledged this as a technical issue:

The fact the free player breaks whenever (for some reason) jwpcdn.com is not available is indeed not good. I was under the impression that loading of that plugin would fail silently, but the free player would still get set up. We’ll investigate what is going on here and how we can gracefully fail loading of this plugin. – 18th June 2013

Now fast forward to JW6.8 – some 7 months later – and the issue still exists.

Hmm… How could this have been over-looked?

To date, these points have been made in the context of the “free-edition” – and maybe that’s why JW find it easy to ignore. In a perverse logic, they want you to pay to remove the functionality that you didn’t want in the first place.

Interesting strategy, but then it’s up to them. You know where they stand, and either you like it or lump it.

But hang on… do you actually know where they stand?

It used to be like this:

With JW6.0 upwards, you simply pay $99 per year, include the documented piece of code in your embed:

analytics: {'enabled': false,'cookies':false}

And you are able to use JW Player without the constraint that you need access to the JW CDN.

But now… with JW6.7:

You pay $300+ per year, you fish around for the (strangely no longer documented) piece of code that you need to include in your embed… and you get the constraints removed.

Clearly it pays for them to over-look this. Fixing this issue would remove a potential incentive for customers to upgrade and impact their increased revenue.

Right… now to the point

Ignoring the disingenuous way the JW Team have covertly moved the “disable analytics” option from a $99 / year edition to a $399+ / year edition without any obvious form of announcement (in fact they’ve hidden the fact this functionality even exists, and they’ve done the same with other key pieces of functionality – HLS on desktop), they really are missing the point.

This problem affects every edition of the player that has analytics enabled…

So… the end-user consumers of a premium paying, Ad feature rich JW provider who embraces analytics, will experience the same “Could not load plugins: File not found” error and no playable video, should the JW CDN not be accessible. This could be because they are on a corporate network with certain external website restrictions, because a DNS issue in their part of the world fails to resolve the JW CDN, or quite simply because the JW CDN fails.

Whilst JW continue to overlook this issue (and boost revenue as a result), you can never be sure your customers are consistently getting the experience you’ve designed for them… and ultimately it’s your income and brand position that would be adversely affected because of this.

It’s not about the “free edition” versus the “premium edition”. It’s about the JW Team respecting and re-engaging with their customers, fixing their code and being honest about their motivations.

About Key Drive for JW Player

The aim of Key Drive for JW Player is to provide full keyboard navigation and control of JW Player media in a bid to make online video/audio more accessible.

Inclusive design features of Key Drive include:

  • Quick interaction through either Tab/Enter key navigation or through common Short-cut keys.
  • Skip links included at the top of the page to quickly enable and access Key Drive.
  • Skip links included to wrap the original video player – allowing Flash or poorly labelled players to be jumped over.
  • Reasonable screen reader support.

Screen reader support

The following screen readers have been used to assist with the development of Key Drive, with mixed results:

  • NVDA – Good results on Firefox and IE. The latest update to Google Chrome [Version 32.0.1700.76 m] has caused NVDA to stop working with it.
  • VoiceOver – Good results – on OS X.
  • ChromeVox – Good results – on Chrome only.
  • Window Eyes – Good results on Firefox and IE. There was an issue with it only announcing the first part of a link in Google Chrome. The latest update to Google Chrome [Version 32.0.1700.76 m] has caused Window Eyes to stop working with it completely.
  • JAWS – Good results on Firefox and IE. Doesn’t work at all with Google Chrome.

It appears that NVDA and Window Eyes will actually work with Chrome – provided ChromeVox has been installed, enabled and then disabled first!

 

Implementing Key Drive

Key Drive for JW Player is a simple JavaScript library which can be loaded as part of the web page design – and hence would be available to all visitors to the page, or can be applied dynamically to the page on a user needs basis – by creating a bookmarklet.

Because Key Drive is a 3rd party library which makes use of the JW Player Application Programming Interface (API), it is compatible across all versions retrospectively and going forward (provided the API supports the functionality).

This means you will not be limited to a particular version of JW Player or the JW Team’s “interpretation” of how accessibility should be implemented (when they get round to addressing it).

Looking forward

Although the specific implementations of rich media support varies quite a bit across browsers and devices, JavaScript support is universally pretty consistent.

Using a similar approach to that taken in developing Key Drive for JW Player, I aim to produce a toolkit of accessibility “aids” which can easily be applied to any web page – with consistency, and independently of the original design or functionality.

Any comments or thoughts regarding this approach would be welcome. You can contact me @jherrieven on twitter.

Try it yourself

You can use Key Drive for JW Player to manage any video on this site by either typing ?jw or by accessing the link via the tab key.

Add it to your site

Adding Key Drive to your site is as simple as including a link to the Key Drive library in your page <HEAD> after the jwplayer.js library, for example:

<!-- JW Player Library -->
<script src="[/path/to/jwplayer]/jwplayer.js"></script>
<!-- Key Drive for JW Player -->
<script src="//www.dev.powered-by-haiku.co.uk/jw-html-config/keydrive/keydrive.min.js?no-splash"></script>

By including the ?no-splash query string as part of the loading URL you can make Key Drive load without displaying the initial dialog.

Load it as a Bookmarklet

A bookmarklet is simply a bookmark stored on your web browser favourites bar (or in the bookmarks folder) that contains JavaScript to dynamically extend the currently loaded page. You can load Key Drive this way by visiting any page with a JW Player on it, and after the page has loaded, copy and paste the following code into your browser URL bar and press return:

javascript:(function(){h=document.getElementsByTagName('head')[0];s=document.createElement('script');s.src='//www.dev.powered-by-haiku.co.uk/jw-html-config/keydrive/keydrive.min.js';h.appendChild(s);void 0;})();

NOTE: Ensure the javascript: part is included – Chrome tends to remove it after you paste into the URL bar.

JW Player 6 doesn’t currently* support WebVTT captions / subtitles when playing video on mobile iOS7. * the current version being 6.7.4071

Here’s how you can fix that…

1) Set up JW Player normally, including the tracks block where applicable:

jwplayer("...").setup({...});

2) Get a handle to the JW instance

var jwp = jwplayer("...");

3) Attach the following onPlay listener

jwp.onPlay(function() {
  if(jwplayer.utils.isIOS()){
    /* Get the video */
    var oVid = jwp.container.getElementsByTagName("video")[0];
    if(oVid){
      /* Remove existing tracks */
      var oTracks = oVid.getElementsByTagName("track");
      if(oTracks){
        for(var tr=oTracks.length,tre=0; tr>=tre; tr--){
          if(oTracks[tr]) oVid.removeChild(oTracks[tr]);
        }
      }
      /* Add this playlist item tracks */
      var oPLI = jwp.getPlaylistItem();
      if(oPLI && oPLI["tracks"] && oPLI["tracks"].length>0){
        for( var tr in oPLI["tracks"]){
          var oTR = oPLI["tracks"][tr];
          var oTrackTag = document.createElement("track");
          for(var attr in oTR){
            var sAttr = (attr=="file"?"src":attr);
            if(attr!="default"||(attr=="default" && oTR[attr]==true)) oTrackTag.setAttribute(sAttr,oTR[attr]);
          }
          oVid.appendChild(oTrackTag);
        }
      }
    }
  }
});

That’s it! Enjoy captioned video on your iPhone.