mirror of
https://github.com/desktop/desktop
synced 2024-09-19 08:02:22 +00:00
Video tag/link markdown filter
This commit is contained in:
parent
2ac089dc11
commit
b67fc6a6c2
|
@ -4,6 +4,8 @@ import { EmojiFilter } from './emoji-filter'
|
|||
import { IssueLinkFilter } from './issue-link-filter'
|
||||
import { IssueMentionFilter } from './issue-mention-filter'
|
||||
import { MentionFilter } from './mention-filter'
|
||||
import { VideoLinkFilter } from './video-link-filter'
|
||||
import { VideoTagFilter } from './video-tag-filter'
|
||||
|
||||
export interface INodeFilter {
|
||||
/**
|
||||
|
@ -44,6 +46,8 @@ export const buildCustomMarkDownNodeFilterPipe = memoizeOne(
|
|||
new IssueLinkFilter(repository),
|
||||
new EmojiFilter(emoji),
|
||||
new MentionFilter(repository),
|
||||
new VideoTagFilter(),
|
||||
new VideoLinkFilter(),
|
||||
]
|
||||
)
|
||||
|
||||
|
|
82
app/src/lib/markdown-filters/video-link-filter.ts
Normal file
82
app/src/lib/markdown-filters/video-link-filter.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
import { INodeFilter } from './node-filter'
|
||||
import { githubAssetVideoRegex } from './video-url-regex'
|
||||
|
||||
/**
|
||||
* The Video Link filter matches a github-flavored markdown target of a link,
|
||||
* like
|
||||
* <p><a href="https://user-images.githubusercontent.com/7559041/1234.mp4">…</a></p>.
|
||||
*
|
||||
* This type of pattern is formed when a user pastes the video url in markdown
|
||||
* editor and then the markdown parser auto links it.
|
||||
*
|
||||
* If the url is in the format of a github user asset, it will replace the
|
||||
* paragraph with link with a a video tag. If not, the link is left unmodified.
|
||||
*/
|
||||
export class VideoLinkFilter implements INodeFilter {
|
||||
/**
|
||||
* Video link matches on p tags with an a tag with a single child of a tag
|
||||
* with an href that's host matches a pattern of video url that is a github
|
||||
* user asset.
|
||||
*/
|
||||
public createFilterTreeWalker(doc: Document): TreeWalker {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const filter = this
|
||||
return doc.createTreeWalker(doc, NodeFilter.SHOW_ELEMENT, {
|
||||
acceptNode: function (el: Element) {
|
||||
return filter.getGithubVideoLink(el) === null
|
||||
? NodeFilter.FILTER_SKIP
|
||||
: NodeFilter.FILTER_ACCEPT
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a paragraph element with a single anchor element that's href appears
|
||||
* to be be a video link and replaces it with a video tag.
|
||||
*
|
||||
* Example:
|
||||
* <p>
|
||||
* <a href="https://user-images.githubusercontent.com/7559041/1234.mp4">
|
||||
* https://user-images.githubusercontent.com/7559041/1234.mp4
|
||||
* </a>
|
||||
* </p>
|
||||
*
|
||||
* Output = [
|
||||
* <videosrc="https://user-images.githubusercontent.com/7559041/1234.mp4"></video>
|
||||
* ]
|
||||
*/
|
||||
public async filter(node: Node): Promise<ReadonlyArray<Node> | null> {
|
||||
const videoSrc = this.getGithubVideoLink(node)
|
||||
if (videoSrc === null) {
|
||||
return null
|
||||
}
|
||||
|
||||
const videoNode = document.createElement('video')
|
||||
videoNode.src = videoSrc
|
||||
return [videoNode]
|
||||
}
|
||||
|
||||
/**
|
||||
* If the give node is a video url post markdown parsing, it returns the video
|
||||
* url, else return null.
|
||||
*
|
||||
* Video url post markdown parsing looks like:
|
||||
* <p>
|
||||
* <a href="https://user-images.githubusercontent.com/7559041/1234.mp4">
|
||||
* https://user-images.githubusercontent.com/7559041/1234.mp4
|
||||
* </a>
|
||||
* </p>
|
||||
* */
|
||||
private getGithubVideoLink(node: Node): string | null {
|
||||
if (
|
||||
node instanceof HTMLParagraphElement &&
|
||||
node.childElementCount === 1 &&
|
||||
node.firstChild instanceof HTMLAnchorElement &&
|
||||
githubAssetVideoRegex.test(node.firstChild.href)
|
||||
) {
|
||||
return node.firstChild.href
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
45
app/src/lib/markdown-filters/video-tag-filter.ts
Normal file
45
app/src/lib/markdown-filters/video-tag-filter.ts
Normal file
|
@ -0,0 +1,45 @@
|
|||
import { INodeFilter } from './node-filter'
|
||||
import { githubAssetVideoRegex } from './video-url-regex'
|
||||
|
||||
/**
|
||||
* The Video Link filter matches embedded video tags, like
|
||||
*
|
||||
* <video src="https://user-images.githubusercontent.com/7559041/1234.mp4"></video>
|
||||
*
|
||||
* If the url for the src does NOT match the pattern of a github user asset, we
|
||||
* remove the video tag.
|
||||
*/
|
||||
export class VideoTagFilter implements INodeFilter {
|
||||
/**
|
||||
* Video link filter matches on video tags that src does not match a github user asset url.
|
||||
*/
|
||||
public createFilterTreeWalker(doc: Document): TreeWalker {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
return doc.createTreeWalker(doc, NodeFilter.SHOW_ELEMENT, {
|
||||
acceptNode: function (el: Element) {
|
||||
return !(el instanceof HTMLVideoElement) ||
|
||||
githubAssetVideoRegex.test(el.src)
|
||||
? NodeFilter.FILTER_SKIP
|
||||
: NodeFilter.FILTER_ACCEPT
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a video element who's src host is not a github user asset url and removes it.
|
||||
*/
|
||||
public async filter(node: Node): Promise<ReadonlyArray<Node> | null> {
|
||||
if (
|
||||
!(node instanceof HTMLVideoElement) ||
|
||||
githubAssetVideoRegex.test(node.src)
|
||||
) {
|
||||
// If it is video element with a valid source, we return null to leave it alone.
|
||||
// This is different then dotcom that regenerates a video tag because it
|
||||
// verifies through a db call that the assets exists
|
||||
return null
|
||||
}
|
||||
|
||||
// Return empty array so that video tag is removed
|
||||
return []
|
||||
}
|
||||
}
|
14
app/src/lib/markdown-filters/video-url-regex.ts
Normal file
14
app/src/lib/markdown-filters/video-url-regex.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { escapeRegExp } from 'lodash'
|
||||
|
||||
const user_images_cdn_url = 'https://user-images.githubusercontent.com'
|
||||
|
||||
// List of common video formats obtained from
|
||||
// https://developer.mozilla.org/en-US/docs/https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Video_codecs/Media/Formats/Video_codecs
|
||||
// The MP4, WebM, and Ogg formats are supported by HTML standard.
|
||||
const videoExtensionRegex = /(mp4|webm|ogg|mov|qt|avi|wmv|3gp|mpg|mpeg|)$/
|
||||
|
||||
/** Regex for checking if a url is a github asset cdn video url */
|
||||
export const githubAssetVideoRegex = new RegExp(
|
||||
escapeRegExp(user_images_cdn_url) + '.+' + videoExtensionRegex.source,
|
||||
'i'
|
||||
)
|
|
@ -284,6 +284,10 @@ changes from the original, just a note that this will not match 1-1)
|
|||
background-color: var(--md-canvas-default-color)
|
||||
}
|
||||
|
||||
.markdown-body video {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.markdown-body img[align=right] {
|
||||
padding-left: 20px
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue