r/javascript • • Jun 22 '16

Those return values though

https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canPlayType
376 Upvotes

75 comments sorted by

97

u/saadq_ Jun 22 '16

'' (empty string): The specified media type definitely cannot be played.

Wish they had used something like "lolnope" instead for that case.

1

u/mcalesy Jun 22 '16
"ithinkso"
"gotmedude"
"hahayouwish"

0

u/[deleted] Jun 22 '16

[deleted]

53

u/[deleted] Jun 22 '16

All they would need to do is have 'lolnope' coerce to false.

25

u/[deleted] Jun 22 '16

that would make for some interesting falsy checks

if (someVar == 'lolnope') return 'gtfo';

13

u/Graftak9000 Jun 22 '16 edited Jun 22 '16

'gfto' should be coerced to null then.

Edit; as for the MDN article, true ('probably'), undefined ('maybe'), and false ('') would be a lot better(?)

9

u/Buckwheat469 Jun 22 '16

Undefined and false evaluate to a false value. In the current implementation the 'maybe' case evaluates to a truthy value so that you can try to play it. You could simply have a time change listener to validate that it's playing.

2

u/Graftak9000 Jun 22 '16

True, but it does allow to say x !== false... or x === true or whatever appropriate combination, which is more explicit as to what behaviour is expected.

0

u/Buckwheat469 Jun 22 '16
!!x !== false
!!x === true

3

u/namesandfaces Jun 22 '16

Or Boolean(x) so that the type conversion is more explicit, although it's not as brief.

0

u/[deleted] Jun 22 '16

[deleted]

→ More replies (0)

4

u/flif Jun 22 '16

It would be much better to return an integer from 0 to 100 as "percent sure it can be played". That would be forward compatible with more than the current 2 values and more robust against e.g. spelling errors.

7

u/flying-sheep Jun 22 '16

No, this is an enum with three semantically different variants:

  1. probably: every check succeeded, sniffing says this is playable. But who knows what kinds of fucked up data they'll send us? (I.e. we want to say true/yes, but we can't promise anything)

  2. maybe: Checks failed, but if they send the right data, maybe we can still get something viewable (I.e. this is inconsistent enough that we need to rely on fault tolerance for any hope of success)

  3. '': Wtf is this shit?

4

u/flif Jun 22 '16

You think it is more advanced than it really is.

They only look at the MIME type, e.g. 'video/mp4' as shown in the example. That is the single argument to the function.

There are no checks besides being able to recognize 'video/mp4', 'video/webm', 'video/ogg' etc.

At this level it should be simple to answer "do I know video/mp4 at all". If you send a garbage file, it will of course fail to play. No reason to include that possibility in the return values.

When they return 'maybe' for video/mp4, it doesn't make sense to have a 'probably' value too. Nothing is more likely to play today on OSX than the mp4 format.

5

u/dysan21 Jun 22 '16 edited Jun 30 '23

Content removed in response to reddit API policies

1

u/flif Jun 22 '16

"maybe" means that it has to get a media file of the particular kind to find out. That might be accessed as 25% chance.

They return "maybe" for "video/mp4" (even Safari does this), so is there any media type which will return "probably"? Is there any other format that is more 'probably' likely to play on e.g. OSX?

1

u/Paul-ish Jun 23 '16

Except then would we hold it to the probably it gives? If it returns 25 would we expect it to work in 25% of our users browsers? How do browser implementers determine that?

-6

u/verbalcontract Jun 22 '16 edited Jun 22 '16

Maybe I'm misreading your statement, but just a reminder: empty strings evaluate to true in JavaScript. !'' evaluates to false. If a function canPlay() returns '' when it can't be played, then !canPlay() would be false when it can't be played.

Too early in the morning for me. (And I could have sworn I had experienced empties returning true before, but maybe it was spaces.)

5

u/phoboslab Jun 22 '16

No. Empty Strings evaluate to false in JavaScript.

console.log(!!"") // false

57

u/[deleted] Jun 22 '16

It would be great for all javascript to be like this. It would make us slow down a bit and chill as a society.

console.log(new Date()) // "one of these days"
console.log(arr.length) // "a few"

0

u/[deleted] Jun 22 '16

[deleted]

25

u/[deleted] Jun 22 '16 edited Jun 22 '16

falsy statements have a random chance to be evaluated as truthy. A whatever event is fired.

2

u/[deleted] Jun 22 '16

Some bullshit library like TrumpScript?

23

u/notunlikethewaves Jun 22 '16

Stringly-typed is best-typed.

4

u/TheNosferatu Jun 22 '16

We already have languages where everything is an object,

Time for a language where everything is a string.

17

u/notunlikethewaves Jun 22 '16

Time for a language where everything is a string.

bash?

-2

u/TheNosferatu Jun 22 '16

Yes, but as a programming language, not a scripting language.

8

u/Otterfan Jun 22 '16

You just aren't trying hard enough.

6

u/TallSkinny Jun 22 '16

I haven't worked with video much, but, is it actually useful is it to distinguish between "maybe" and "probably"? I feel like you'd want to try to play it in either case, and if it fails, you should be handling that gracefully anyways. "Maybe" and "yes" I could potentially see handling differently, but even then I'd probably still try.

13

u/Shaper_pmp Jun 22 '16

is it actually useful is it to distinguish between "maybe" and "probably"

From a UX perspective, yeah, "probably". :-D

More seriously, the problem here is that media containers/codecs/streaming is fundamentally broken in that a computer can't possibly know whether it can play a given stream or file until it tries, and catches any errors that occur.

Given that fundamental gap in functionality, "definitely not" (""), "maybe" and "probably" are the best the browser can do. Certainly it's better than reporting true/false/null, that naive devs may take as gospel but which may be highly inaccurate for many users.

4

u/blood_bender Jun 22 '16

Well, .play() does return a promise which will be rejected if it fails for any reason, so you're right.

But it's a usability type of thing. If the result is maybe, you probably want to display a warning saying "This media may not work on your device" or whatever. But in the simpler case as you're suggesting, just check for truthyness if (m.canPlayType()).

2

u/hufman Jun 22 '16

Well, .play() does return a promise

Except on iOS Safari ;)

-1

u/TheNosferatu Jun 22 '16

Wait, people use that?

9

u/hufman Jun 22 '16

As far as I know, every browser on iPhone and iPad is required to use Apple's native javascript engine. This means that every iPhone and iPad user must be treated specially, needing to check the return of .play before using it as a promise.

:/ Just got bit by this.

5

u/third-eye-brown Jun 22 '16

Only several dozen million.

6

u/[deleted] Jun 22 '16

shrug At least they document their return values.

API docs that make no mention of possible exceptions or return values are one of my pet peeves.

5

u/Semperdark Jun 23 '16

Can you imagine if they didn't document it, and you got a "probably" from something you were expecting to be boolean? I think I'd just quit programming.

4

u/dtfinch Jun 22 '16

It could be handy to notice that "probably">"maybe", so you can pick the type that has the greatest return value.

2

u/ishouldrlybeworking Jun 22 '16

What kind of actions would an application take if it got back 'maybe' vs 'probably'? It seems like in either case the application would attempt to play the media so the distinction is useless. It may as well be refactored to .cannotPlayType() which returns true if media is definitely unplayable, false otherwise.

3

u/NavarrB Jun 22 '16

I assume choosing which media to attempt to play.

You might have a list of media types available and choose whichever "probably" over a "maybe"

2

u/jim45804 Jun 22 '16

Fuzzy logic return values, I like it.

1

u/[deleted] Jun 22 '16

Seems like this one was designed to be wrapped and not used directly.

1

u/regreddit Jun 22 '16

"mehgiveitashot"

"mightgetlucky"

"crossyourfingers"

1

u/[deleted] Jun 23 '16

It's all just people

-11

u/[deleted] Jun 22 '16

So ... okay ... when did the Mozilla developers lost their minds?

14

u/protestor Jun 22 '16

The issue is that sometimes all you got is a mime-type, which isn't enough to decide whether something is playable. That is, unless you attempt to play.

Example: the mime-type video/mp4 doesn't say what are the codecs inside this mp4, so you get a "maybe". But if you get a more descriptive string like video/mp4; codecs="avc1.42E01E, mp4a.40.2", you will get a "probably" (if the browser supports playing H.264 and AAC, that is)

Well why "probably" instead of "yes"? Well here the browser is just being honest. The user may have installed a buggy GPU driver or something.

Now, returning an empty string instead of null is inexcusable.

12

u/mmmicahhh Jun 22 '16

Inexcusable? Why would null be a better choice here?

  • A semantic refusal would be false (responding to the can play question in the function name)

  • Both null and false would introduce situations where a function returns different types at different points, which is even worse than the current solution.

4

u/Tiquortoo Jun 22 '16

probably now allows for a future value of yes, if that certainty can ever be achieved, without breaking everything.

4

u/kovensky Jun 22 '16

Even things unrelated to buggy GPU drivers. For example, older hardware decoders would accept H.264 High Profile Level 4.1 (the maximum that a BD was allowed to use, at least back then), but would refuse Level 5.0 streams, even if the stream itself stayed within Level 4.1 limits.

Thus, unless you have a really detailed MIME type that includes even the H.264 header in it, you can't tell if your decoder would accept it until you try it.

-1

u/PlNG Jun 22 '16

True, Undefined, False.

Why deviate from that for fucks sakes.

6

u/Shaper_pmp Jun 22 '16 edited Jun 22 '16

Because you can't possibly know if the computer can play every file based just on the mimetype (hell, even specifying the codec isn't always perfectly reliable). A lot of the time you just have to try and play and see if an error occurs. This is a flaw in the mimetype header/media playing in general, not in the browser or JS API.

Given that it's impossible to ever know for sure whether a particular URL can be played ahead of time, returning true is incredibly misleading, and more or less guarantees naive devs will fall over it all the time, leading to unreliable or broken code, errors in production, etc, etc, etc.

At least if they look up the API details and see it returns "maybe"/"probably" that's a really big hint that there's a huge unknown in play, and they should investigate further to ensure they understand the issues involved.

0

u/Fs0i Jun 22 '16

Because you can't return "true" in many cases.

5

u/lachlanhunt Jun 22 '16

It's actually intentional because the empty string if falsey, and the other two, "probably" and "maybe" are truthy. It was done like that because a naive check using if (video.canPlayType("video/mp4")) will type cast in a sensible way, while allowing the more specific values to be checked for more granular control when selecting the media type to play. It just expresses the confidence level in being able to play a certain type of media based on the content type, which is as reliable as possible before inspecting the actual file to see what's in it.

2

u/vinnl Jun 22 '16

It's not Mozilla, it's what WHATWG (or the W3C?). And they're limited by Javascript although usually, numbers are used instead of strings to compensate for the lack of enums or something else.

2

u/Shaper_pmp Jun 22 '16

This is nonsense. The problem is that with the wide variety of codecs and container types it's often impossible to know if a given browser can play a given file without actually requesting it and trying, so all this API call can do is give a best-guess (hence the weird return types to make that abundantly clear to the developer using it).

It's true that JS doesn't have enums, but that's a distinctly side-issue, and it could be easily worked around by defining HTMLMediaElement.PROBABLY = 1; HTMLMediaElement.MAYBE = 2;, etc. JS devs do this all the time to avoid magic numbers in their code.

The problem is that 1 doesn't scream "you can't rely on the result of this query" every time you look at the code, whereas "probably" is almost impossible to miss.

1

u/vinnl Jun 22 '16

Yeah it's pretty logical that they're using strings, I was merely pointing out that "weird" return types happen far more often.

Using properties wouldn't be that good of a solution, as they can be overwritten. Since last year, though, symbols could've been an option.

0

u/jijilento Jun 22 '16

Yea, large parts of the webaudio api operate on magic numbers so like 4 would represent playable in a method (I don't have the documentation in front of me). I'm not sure why they couldn't polyfill enums for these complex returns.

0

u/[deleted] Jun 22 '16

[deleted]

0

u/[deleted] Jun 22 '16

[deleted]

1

u/flying-sheep Jun 22 '16

Isn't that called “life”?

-5

u/delventhalz Jun 22 '16

'probably' and 'maybe' mean the same thing to my ear. Something like 'likely' and 'possibly' might have drawn a better distinction. The empty string makes sense though. I love me some falsey values.

12

u/Fs0i Jun 22 '16

Probably denotes that it's more likely than not (probability > 50%), "maybe" just says probability > 0%.

-2

u/delventhalz Jun 22 '16

Sure. Just saying there are different words that would make the semantic distinction more clear. In life, I would say "probably" and "maybe" in similar circumstances, even though they mean different things.

0

u/[deleted] Jun 22 '16

[deleted]

6

u/inu-no-policemen Jun 22 '16

What you actually want there is an enum, but JavaScript doesn't support those.

TypeScript and Dart do have enums. TypeScript even has string types for exactly this kind of situation.

6

u/Fs0i Jun 22 '16

Yep. This function has the return-type "maybe" | "probably" | "" in TypeScript. Super helpful :)