Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added video subtitle and alt text checks #795

Merged
merged 1 commit into from
May 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/linter/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { SxgDumpSignedExchangeVerify } from "./rules/SxgDumpSignedExchangeVerify
import { SxgAmppkgIsForwarded } from "./rules/SxgAmppkgIsForwarded";
import { MetadataIncludesOGImageSrc } from "./rules/MetadataIncludesOGImageSrc";
import { ImagesHaveAltText } from "./rules/ImagesHaveAltText";
import { VideosHaveAltText } from "./rules/VideosHaveAltText";
import { VideosAreSubtitled } from "./rules/VideosAreSubtitled";
import { IsValid } from "./rules/IsValid";
import { RuleConstructor } from "./rule";
import { isArray } from "util";
Expand Down Expand Up @@ -106,6 +108,8 @@ function testsForMode(type: LintMode) {
StoryMetadataThumbnailsAreOk,
MetadataIncludesOGImageSrc,
ImagesHaveAltText,
VideosHaveAltText,
VideosAreSubtitled,
])
);
return tests.get(type) || [];
Expand Down
21 changes: 21 additions & 0 deletions packages/linter/src/rules/VideosAreSubtitled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Context } from "../index";
import { Rule } from "../rule";

export class VideosAreSubtitled extends Rule {
run({ $ }: Context) {
const numOfSubtitleElems = $("track").length;
const numOfVideoElems = $("amp-video").length;

//Are there any <amp-video> tags? If so, is there at least 1 <track>?
return numOfVideoElems > 0 && numOfSubtitleElems <= 0
? this.warn(`One or more videos are missing HMTL subtitles`)
: this.pass();
}
meta() {
return {
url: "https://blog.amp.dev/2020/02/12/seo-for-amp-stories/",
title: "Videos are subtitled",
info: "",
};
}
}
25 changes: 25 additions & 0 deletions packages/linter/src/rules/VideosHaveAltText.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Context } from "../index";
import { Rule } from "../rule";

export class VideosHaveAltText extends Rule {
run({ $ }: Context) {
let vidsWithoutAlt = 0;

$("amp-video").each(function (i, elem) {
if (!elem.attribs.title) {
vidsWithoutAlt += 1;
}
});

return vidsWithoutAlt > 0
? this.warn(`Missing alt text from ${vidsWithoutAlt} videos`)
: this.pass();
}
meta() {
return {
url: "https://blog.amp.dev/2020/02/12/seo-for-amp-stories/",
title: "Videos contain alt text",
info: "",
};
}
}
24 changes: 23 additions & 1 deletion packages/linter/tests/local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { SchemaMetadataIsNews } from "../src/rules/SchemaMetadataIsNews";
import { StoryRuntimeIsV1 } from "../src/rules/StoryRuntimeIsV1";
import { ImagesHaveAltText } from "../src/rules/ImagesHaveAltText";
import { MetadataIncludesOGImageSrc } from "../src/rules/MetadataIncludesOGImageSrc";
import { VideosHaveAltText } from "../src/rules/VideosHaveAltText";
import { VideosAreSubtitled } from "../src/rules/VideosAreSubtitled";
import { basename } from "path";
import { BookendExists } from "../src/rules/BookendExists";

Expand Down Expand Up @@ -130,5 +132,25 @@ assertWarn(
runLocalTest(ImagesHaveAltText, "local/ImagesHaveAltText-2/source.html")
);

assertPass(
`${VideosHaveAltText.name} - All <amp-video> have alt text`,
runLocalTest(VideosHaveAltText, "local/VideosHaveAltText-1/source.html")
);

assertWarn(
`${VideosHaveAltText.name} - At least one <amp-video> is missing alt text`,
runLocalTest(VideosHaveAltText, "local/VideosHaveAltText-2/source.html")
);

assertPass(
`${VideosAreSubtitled.name} - All <amp-video> have subtitles`,
runLocalTest(VideosAreSubtitled, "local/VideosAreSubtitled-1/source.html")
);

assertWarn(
`${VideosAreSubtitled.name} - One or more <amp-video> are missing subtitles`,
runLocalTest(VideosAreSubtitled, "local/VideosAreSubtitled-2/source.html")
);

console.log(`# ${basename(__filename)} - HTML-only tests`);
console.log(`1..20`);
console.log(`1..24`);
33 changes: 33 additions & 0 deletions packages/linter/tests/local/VideosAreSubtitled-1/source.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!doctype html>
<html amp lang="en">
<head>
<meta charset="utf-8">
<script async src="https://cdn.ampproject.org/v0.js"></script>
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style>
<noscript>
<style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style>
</noscript>
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<script async custom-element="amp-analytics" src="https://cdn.ampproject.org/v0/amp-analytics-0.1.js"></script> <script async custom-element="amp-video" src="https://cdn.ampproject.org/v0/amp-video-0.1.js"></script>
<title>Subtitle Test</title>
<script async custom-element="amp-story" src="https://cdn.ampproject.org/v0/amp-story-1.0.js"></script>
<link rel="shortcut icon" href="https://app.makestories.io/images/favicon.png" type="image/x-icon">
<link rel="canonical" href="https://onl.st/subtitle-test/">
<style amp-custom>.pbuoprw#pbvqloxifffxp video{object-fit:cover;max-width:unset;max-height:unset;height:100%;left:0;top:0;width:100%}amp-img{position:relative}.content-block{padding:10px 15px}.block{position:relative;padding:5px;word-break:break-word}.content-block amp-video{display:block;margin:0 auto}.content-block>hr{padding:0;margin:5px 0;border-top:1px solid #eee}.block a{color:inherit;text-decoration:none}h1,h2,h3,h4,h5,h6,p{padding:0;margin:0}.cta-a{text-decoration:none;display:flex;align-items:center}.cta-a span{width:100%}.svg-el svg{display:block;width:100%;height:100%}.block .cta-a{padding:.3em 1em;display:inline-block}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.cta-a amp-img{width:100%;height:100%}.cta-a amp-img img{height:100%;width:100%;min-height:unset}.flip-vertically img{transform:rotateY(180deg)}.flip-horizontally img{transform:rotateX(180deg)}.flip-horizontally.flip-vertically img{transform:rotateX(180deg) rotateY(180deg)}.pa{position:absolute;word-break:break-word}.img-fill,a.story-tooltip{top:0;left:0;width:100%;height:100%}a.story-tooltip{z-index:1;text-decoration:none;color:inherit}.offset{transform:translateX(-50%) translateY(-50%)}.oh{overflow:hidden}.pa.kbimg{width:0;height:0}amp-story{font-size:3.125vw}@media screen and (min-aspect-ratio:5/8){amp-story{font-size:2.95vw}}@media screen and (min-width:1024px){amp-story{font-size:1.8vh}}@media screen and (min-width:1024px) and (max-height:660px){amp-story{font-size:1.8vh}}::cue{background-color:rgba(0,0,0,.75);font-size:24px;line-height:1.5}@media screen and (min-width:768px) and (max-width:1024px){amp-story{font-size:130%}}</style>
</head>
<body>
<amp-story standalone poster-portrait-src="https://ss.makestories.io/get?story=-M7d0U5_iOxv_iRRUsOg&version=1589826244967&width=696&height=1237" publisher-logo-src="https://app.makestories.io/images/favicon.png" publisher="MakeStories" title="New Story">
<amp-story-page id="qloxifffxp" class="qloxifffxp ms-st-pg">
<amp-story-grid-layer template="fill" class="pbuoprwp">
<amp-video class="pbuoprw" layout="responsive" width="720" height="1280" poster="https://storage.coverr.co/t/okK00ZCLobn6HIIDsmY2902TRcqo006ISsJ" autoplay id="pbvqloxifffxp">
<source src="https://storage.coverr.co/videos/okK00ZCLobn6HIIDsmY2902TRcqo006ISsJ?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBJZCI6IjZEODdDRTIyODUxQzg3MTlGRUYyIiwiaWF0IjoxNTg5ODI2MTU3fQ.AxxQs0QUH4slLNk85pcvaIh0OGorVv9p_CUMIjinioU" type="video/mp4">
<track kind="subtitles" srclang="en_US" src="https://makestories-staging.firebaseapp.com/subtitles?url=" default>
</amp-video>
</amp-story-grid-layer>
<amp-story-grid-layer template="vertical" id="sotfa"> </amp-story-grid-layer>
</amp-story-page>
<amp-analytics config="https://makestories-staging.firebaseapp.com/analytics?storyId=-M7d0U5_iOxv_iRRUsOg"></amp-analytics>
<amp-story-bookend src="bookend.json" layout="nodisplay"></amp-story-bookend>
</amp-story>
</body>
</html>
32 changes: 32 additions & 0 deletions packages/linter/tests/local/VideosAreSubtitled-2/source.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!doctype html>
<html amp lang="en">
<head>
<meta charset="utf-8">
<script async src="https://cdn.ampproject.org/v0.js"></script>
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style>
<noscript>
<style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style>
</noscript>
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<script async custom-element="amp-analytics" src="https://cdn.ampproject.org/v0/amp-analytics-0.1.js"></script> <script async custom-element="amp-video" src="https://cdn.ampproject.org/v0/amp-video-0.1.js"></script>
<title>Subtitle Test</title>
<script async custom-element="amp-story" src="https://cdn.ampproject.org/v0/amp-story-1.0.js"></script>
<link rel="shortcut icon" href="https://app.makestories.io/images/favicon.png" type="image/x-icon">
<link rel="canonical" href="https://onl.st/subtitle-test/">
<style amp-custom>.pbuoprw#pbvqloxifffxp video{object-fit:cover;max-width:unset;max-height:unset;height:100%;left:0;top:0;width:100%}amp-img{position:relative}.content-block{padding:10px 15px}.block{position:relative;padding:5px;word-break:break-word}.content-block amp-video{display:block;margin:0 auto}.content-block>hr{padding:0;margin:5px 0;border-top:1px solid #eee}.block a{color:inherit;text-decoration:none}h1,h2,h3,h4,h5,h6,p{padding:0;margin:0}.cta-a{text-decoration:none;display:flex;align-items:center}.cta-a span{width:100%}.svg-el svg{display:block;width:100%;height:100%}.block .cta-a{padding:.3em 1em;display:inline-block}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.cta-a amp-img{width:100%;height:100%}.cta-a amp-img img{height:100%;width:100%;min-height:unset}.flip-vertically img{transform:rotateY(180deg)}.flip-horizontally img{transform:rotateX(180deg)}.flip-horizontally.flip-vertically img{transform:rotateX(180deg) rotateY(180deg)}.pa{position:absolute;word-break:break-word}.img-fill,a.story-tooltip{top:0;left:0;width:100%;height:100%}a.story-tooltip{z-index:1;text-decoration:none;color:inherit}.offset{transform:translateX(-50%) translateY(-50%)}.oh{overflow:hidden}.pa.kbimg{width:0;height:0}amp-story{font-size:3.125vw}@media screen and (min-aspect-ratio:5/8){amp-story{font-size:2.95vw}}@media screen and (min-width:1024px){amp-story{font-size:1.8vh}}@media screen and (min-width:1024px) and (max-height:660px){amp-story{font-size:1.8vh}}::cue{background-color:rgba(0,0,0,.75);font-size:24px;line-height:1.5}@media screen and (min-width:768px) and (max-width:1024px){amp-story{font-size:130%}}</style>
</head>
<body>
<amp-story standalone poster-portrait-src="https://ss.makestories.io/get?story=-M7d0U5_iOxv_iRRUsOg&version=1589826244967&width=696&height=1237" publisher-logo-src="https://app.makestories.io/images/favicon.png" publisher="MakeStories" title="New Story">
<amp-story-page id="qloxifffxp" class="qloxifffxp ms-st-pg">
<amp-story-grid-layer template="fill" class="pbuoprwp">
<amp-video class="pbuoprw" layout="responsive" width="720" height="1280" poster="https://storage.coverr.co/t/okK00ZCLobn6HIIDsmY2902TRcqo006ISsJ" autoplay id="pbvqloxifffxp">
<source src="https://storage.coverr.co/videos/okK00ZCLobn6HIIDsmY2902TRcqo006ISsJ?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBJZCI6IjZEODdDRTIyODUxQzg3MTlGRUYyIiwiaWF0IjoxNTg5ODI2MTU3fQ.AxxQs0QUH4slLNk85pcvaIh0OGorVv9p_CUMIjinioU" type="video/mp4">
</amp-video>
</amp-story-grid-layer>
<amp-story-grid-layer template="vertical" id="sotfa"> </amp-story-grid-layer>
</amp-story-page>
<amp-analytics config="https://makestories-staging.firebaseapp.com/analytics?storyId=-M7d0U5_iOxv_iRRUsOg"></amp-analytics>
<amp-story-bookend src="bookend.json" layout="nodisplay"></amp-story-bookend>
</amp-story>
</body>
</html>
33 changes: 33 additions & 0 deletions packages/linter/tests/local/VideosHaveAltText-1/source.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

<!doctype html>
<html amp lang="en">
<head>
<meta charset="utf-8">
<script async src="https://cdn.ampproject.org/v0.js"></script>
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style>
<noscript>
<style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style>
</noscript>
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<script async custom-element="amp-analytics" src="https://cdn.ampproject.org/v0/amp-analytics-0.1.js"></script> <script async custom-element="amp-video" src="https://cdn.ampproject.org/v0/amp-video-0.1.js"></script>
<title>Highway views</title>
<script async custom-element="amp-story" src="https://cdn.ampproject.org/v0/amp-story-1.0.js"></script>
<link rel="shortcut icon" href="https://app.makestories.io/images/favicon.png" type="image/x-icon">
<link rel="canonical" href="https://onl.st/title-test/">
<style amp-custom>.pbrtkfp#pbvrttrilkynd video{object-fit:cover;max-width:unset;max-height:unset;height:100%;left:0;top:0;width:100%}amp-img{position:relative}.content-block{padding:10px 15px}.block{position:relative;padding:5px;word-break:break-word}.content-block amp-video{display:block;margin:0 auto}.content-block>hr{padding:0;margin:5px 0;border-top:1px solid #eee}.block a{color:inherit;text-decoration:none}h1,h2,h3,h4,h5,h6,p{padding:0;margin:0}.cta-a{text-decoration:none;display:flex;align-items:center}.cta-a span{width:100%}.svg-el svg{display:block;width:100%;height:100%}.block .cta-a{padding:.3em 1em;display:inline-block}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.cta-a amp-img{width:100%;height:100%}.cta-a amp-img img{height:100%;width:100%;min-height:unset}.flip-vertically img{transform:rotateY(180deg)}.flip-horizontally img{transform:rotateX(180deg)}.flip-horizontally.flip-vertically img{transform:rotateX(180deg) rotateY(180deg)}.pa{position:absolute;word-break:break-word}.img-fill,a.story-tooltip{top:0;left:0;width:100%;height:100%}a.story-tooltip{z-index:1;text-decoration:none;color:inherit}.offset{transform:translateX(-50%) translateY(-50%)}.oh{overflow:hidden}.pa.kbimg{width:0;height:0}amp-story{font-size:3.125vw}@media screen and (min-aspect-ratio:5/8){amp-story{font-size:2.95vw}}@media screen and (min-width:1024px){amp-story{font-size:1.8vh}}@media screen and (min-width:1024px) and (max-height:660px){amp-story{font-size:1.8vh}}::cue{background-color:rgba(0,0,0,.75);font-size:24px;line-height:1.5}@media screen and (min-width:768px) and (max-width:1024px){amp-story{font-size:130%}}</style>
</head>
<body>
<amp-story standalone poster-portrait-src="https://ss.makestories.io/get?story=-M7d-cM7tWxC2lbBoR82&version=1589827224057&width=696&height=1237" publisher-logo-src="https://app.makestories.io/images/favicon.png" publisher="MakeStories" title="Highway views">
<amp-story-page id="rttrilkynd" class="rttrilkynd ms-st-pg">
<amp-story-grid-layer template="fill" class="pbrtkfpp">
<amp-video class="pbrtkfp" layout="responsive" width="720" height="1280" poster="https://storage.coverr.co/t/slksQfq6th47M4cA02OsxRE00cWFPs5otT" autoplay title="Highway View" id="pbvrttrilkynd">
<source src="https://storage.coverr.co/videos/slksQfq6th47M4cA02OsxRE00cWFPs5otT?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBJZCI6IjZEODdDRTIyODUxQzg3MTlGRUYyIiwiaWF0IjoxNTg5ODI2NTYzfQ.E6N_54dX5M9FaVqvw_s3uhuZuZUECb2wJxevyJqVEW0" type="video/mp4">
</amp-video>
</amp-story-grid-layer>
<amp-story-grid-layer template="vertical" id="sirsv"> </amp-story-grid-layer>
</amp-story-page>
<amp-analytics config="https://makestories-staging.firebaseapp.com/analytics?storyId=-M7d-cM7tWxC2lbBoR82"></amp-analytics>
<amp-story-bookend src="bookend.json" layout="nodisplay"></amp-story-bookend>
</amp-story>
</body>
</html>
Loading