diff --git a/README.md b/README.md
index 86eb1e6..fd3ee02 100644
--- a/README.md
+++ b/README.md
@@ -61,6 +61,7 @@ One way to ensure all dependencies are loaded is to use the [`@wordpress/depende
- [`useActiveBlockStyle`](src/hooks/useActiveBlockStyle)
- [`useBlockStyles`](src/hooks/useBlockStyles)
- [`useDisallowedBlocks`](src/hooks/useDisallowedBlocks)
+- [`useMediaSrc`](src/hooks/useMediaSrc)
- [`useMeta`](src/hooks/useMeta)
- [`useRenderAppenderWithBlockLimit`](src/hooks/useRenderAppenderWithBlockLimit)
- [`useSelectBlock`](src/hooks/useSelectBlock)
diff --git a/src/hooks/useMediaSrc/README.md b/src/hooks/useMediaSrc/README.md
new file mode 100644
index 0000000..b97f3e9
--- /dev/null
+++ b/src/hooks/useMediaSrc/README.md
@@ -0,0 +1,45 @@
+# useMediaSrc
+
+The `useMediaSrc` hook allows for the easy retrieval of source media URLs from an ID.
+
+## Usage
+
+The `useMediaSrc` hook takes an ID and returns a URL or undefined.
+
+```js
+import { useMediaSrc } from '@humanmade/block-editor-components';
+
+function BlockEdit( { attributes, setAttributes } ) {
+ const {
+ videoId
+ } = attributes;
+ const videoUrl = useMediaSrc( videoId );
+
+ return (
+ <>
+
+
+ setAttributes( { videoId: media.id } )
+ }
+ value={ videoId }
+ render={ ( { open } ) => (
+
+ ) }
+ />
+
+
+ <>
+ );
+}
+```
+
+## Return
+
+The `useMediaSrc` hook returns either a URL string or undefined.
+
+## Dependencies
+
+The `useMediaSrc` hook requires the following dependencies, which are expected to be available:
+
+- `@wordpress/data`
diff --git a/src/hooks/useMediaSrc/index.js b/src/hooks/useMediaSrc/index.js
new file mode 100644
index 0000000..6d52e6f
--- /dev/null
+++ b/src/hooks/useMediaSrc/index.js
@@ -0,0 +1,21 @@
+import { useSelect } from '@wordpress/data';
+
+/**
+ * Returns the original source URL of media if available, or undefined, given an ID.
+ *
+ * @param {number} id attachment ID.
+ * @returns {string|undefined} Media source URL or undefined.
+ */
+export default function useMediaSrc( id ) {
+ const url = useSelect(
+ ( select ) => {
+ const media = select( 'core' ).getMedia( id, { context: 'view' } );
+ if ( ! media ) {
+ return undefined;
+ }
+ return media.source_url;
+ },
+ [ id ]
+ );
+ return url;
+}
diff --git a/src/hooks/usePostThumbnail/index.js b/src/hooks/usePostThumbnail/index.js
index d6ef416..c4e1452 100644
--- a/src/hooks/usePostThumbnail/index.js
+++ b/src/hooks/usePostThumbnail/index.js
@@ -36,7 +36,7 @@ export default function usePostThumbnail() {
const setPostThumbnail = useCallback(
( mediaId ) => {
- // If the image has been removed, we can remove the post thumbnail.
+ // If the image has been removed, we can remove the post thumbnail.
editPost( { featured_media: mediaId } );
},
[ editPost ]
diff --git a/src/index.js b/src/index.js
index 4f9abd8..474a994 100644
--- a/src/index.js
+++ b/src/index.js
@@ -23,6 +23,7 @@ export {
export { default as useActiveBlockStyle } from './hooks/useActiveBlockStyle';
export { default as useBlockStyles } from './hooks/useBlockStyles';
export { default as useDisallowedBlocks } from './hooks/useDisallowedBlocks';
+export { default as useMediaSrc } from './hooks/useMediaSrc';
export { default as useMeta } from './hooks/useMeta';
export { default as usePostThumbnail } from './hooks/usePostThumbnail';
export { default as useRenderAppenderWithBlockLimit } from './hooks/useRenderAppenderWithBlockLimit';