Repository: yt-dlp/yt-dlp

Issue:
Unsupported URL: fathom.video
### DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE

- [X] I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field

### Checklist

- [X] I'm reporting a new site support request
- [X] I've verified that I'm running yt-dlp version **2023.10.13** ([update instructions](https://github.com/yt-dlp/yt-dlp#update)) or later (specify commit)
- [X] I've checked that all provided URLs are playable in a browser with the same IP and same login details
- [X] I've checked that none of provided URLs [violate any copyrights](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#is-the-website-primarily-used-for-piracy) or contain any [DRM](https://en.wikipedia.org/wiki/Digital_rights_management) to the best of my knowledge
- [X] I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues **including closed ones**. DO NOT post duplicates
- [X] I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
- [X] I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and am willing to share it if required

### Region

_No response_

### Example URLs

- Single video: https://fathom.video/share/G9mkjkspnohVVZ_L5nrsoPycyWcB8y7s

### Provide a description that is worded well enough to be understood

The website fathom.video is not supported by yt-dlp yet. I've pasted the verbose below. 

I'm submitting this issue to request adding an extractor for this website.

Thanks!

### Provide verbose output that clearly demonstrates the problem

- [X] Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
- [X] If using API, add `'verbose': True` to `YoutubeDL` params instead
- [X] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below

### Complete Verbose Output

```shell
[debug] Command-line config: ['-J', '-vU', 'https://fathom.video/share/G9mkjkspnohVVZ_L5nrsoPycyWcB8y7s']
[debug] Encodings: locale UTF-8, fs utf-8, pref UTF-8, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version nightly@2023.10.28.155411 [4a601c9ef] (zip)
[debug] Python 3.8.10 (CPython x86_64 64bit) - Linux-5.4.0-153-generic-x86_64-with-glibc2.29 (OpenSSL 1.1.1f  31 Mar 2020, glibc 2.31)
[debug] exe versions: none
[debug] Optional libraries: certifi-2019.11.28, requests-2.22.0, sqlite3-3.31.1, urllib3-1.25.8
[debug] Proxy map: {}
[debug] Request Handlers: urllib
[debug] Loaded 1890 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest
Available version: nightly@2023.10.28.155411, Current version: nightly@2023.10.28.155411
Current Build Hash: 571d1fa9feeab2d00113dd890b62b8e06e25ba9ed5b968d22f300b7b5eb0b96a
yt-dlp is up to date (nightly@2023.10.28.155411)
[generic] Extracting URL: https://fathom.video/share/G9mkjkspnohVVZ_L5nrsoPycyWcB8y7s
[generic] G9mkjkspnohVVZ_L5nrsoPycyWcB8y7s: Downloading webpage
WARNING: [generic] Falling back on generic information extractor
[generic] G9mkjkspnohVVZ_L5nrsoPycyWcB8y7s: Extracting information
[debug] Looking for embeds
ERROR: Unsupported URL: https://fathom.video/share/G9mkjkspnohVVZ_L5nrsoPycyWcB8y7s
Traceback (most recent call last):
  File "/usr/local/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 1567, in wrapper
    return func(self, *args, **kwargs)
  File "/usr/local/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 1702, in __extract_info
    ie_result = ie.extract(url)
  File "/usr/local/bin/yt-dlp/yt_dlp/extractor/common.py", line 715, in extract
    ie_result = self._real_extract(url)
  File "/usr/local/bin/yt-dlp/yt_dlp/extractor/generic.py", line 2577, in _real_extract
    raise UnsupportedError(url)
yt_dlp.utils.UnsupportedError: Unsupported URL: https://fathom.video/share/G9mkjkspnohVVZ_L5nrsoPycyWcB8y7s

null
```



Discussion:
m3u8 manifest https://fathom.video/share/G9mkjkspnohVVZ_L5nrsoPycyWcB8y7s/video.m3u8 is the `props.call.video_url` member of the HTML-encoded JSON object found as `data-page` attribute of the `div#app` element in the non-JS page. Other metadata is available there too.
Same issue in every way.
---
[debug] Command-line config: ['-vU', 'https://fathom.video/share/mEws3bybftHL2QLymxYEDeE21vtLxGVm']
[debug] Encodings: locale cp1252, fs utf-8, pref cp1252, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version stable@2023.09.24 [088add956] (win_exe)
[debug] Python 3.8.10 (CPython AMD64 64bit) - Windows-10-10.0.22621-SP0 (OpenSSL 1.1.1k  25 Mar 2021)
[debug] exe versions: ffmpeg 5.1-essentials_build-www.gyan.dev (setts), ffprobe 5.1-essentials_build-www.gyan.dev
[debug] Optional libraries: Cryptodome-3.19.0, brotli-1.1.0, certifi-2023.07.22, mutagen-1.47.0, sqlite3-3.35.5, websockets-11.0.3
[debug] Proxy map: {}
[debug] Loaded 1886 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Available version: stable@2023.10.13, Current version: stable@2023.09.24
Current Build Hash: 125465ac4416bcd4bf1632b899630ceecc08b341e83fdf10bd34700c58ea5152
[debug] Downloading _update_spec from https://github.com/yt-dlp/yt-dlp/releases/latest/download/_update_spec
Updating to stable@2023.10.13 ...
[debug] Downloading yt-dlp.exe from https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe
[debug] Downloading SHA2-256SUMS from https://github.com/yt-dlp/yt-dlp/releases/latest/download/SHA2-256SUMS
Updated yt-dlp to stable@2023.10.13
[debug] Restarting: yt-dlp.exe -vU "https://fathom.video/share/mEws3bybftHL2QLymxYEDeE21vtLxGVm"
[debug] Command-line config: ['-vU', 'https://fathom.video/share/mEws3bybftHL2QLymxYEDeE21vtLxGVm']
[debug] Encodings: locale cp1252, fs utf-8, pref cp1252, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version stable@2023.10.13 [b634ba742] (win_exe)
[debug] Python 3.8.10 (CPython AMD64 64bit) - Windows-10-10.0.22621-SP0 (OpenSSL 1.1.1k  25 Mar 2021)
[debug] exe versions: ffmpeg 5.1-essentials_build-www.gyan.dev (setts), ffprobe 5.1-essentials_build-www.gyan.dev
[debug] Optional libraries: Cryptodome-3.19.0, brotli-1.1.0, certifi-2023.07.22, mutagen-1.47.0, sqlite3-3.35.5, websockets-11.0.3
[debug] Proxy map: {}
[debug] Loaded 1890 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Available version: stable@2023.10.13, Current version: stable@2023.10.13
Current Build Hash: 13d6a04ef6678dc61cb6e2d42eb53e69486bd2f52b8e5d778db029ccd4c600b4
yt-dlp is up to date (stable@2023.10.13)
[generic] Extracting URL: https://fathom.video/share/mEws3bybftHL2QLymxYEDeE21vtLxGVm
[generic] mEws3bybftHL2QLymxYEDeE21vtLxGVm: Downloading webpage
WARNING: [generic] Falling back on generic information extractor
[generic] mEws3bybftHL2QLymxYEDeE21vtLxGVm: Extracting information
[debug] Looking for embeds
ERROR: Unsupported URL: https://fathom.video/share/mEws3bybftHL2QLymxYEDeE21vtLxGVm
Traceback (most recent call last):
  File "yt_dlp\YoutubeDL.py", line 1567, in wrapper
  File "yt_dlp\YoutubeDL.py", line 1702, in __extract_info
  File "yt_dlp\extractor\common.py", line 715, in extract
  File "yt_dlp\extractor\generic.py", line 2575, in _real_extract
yt_dlp.utils.UnsupportedError: Unsupported URL: https://fathom.video/share/mEws3bybftHL2QLymxYEDeE21vtLxGVm
Another example of it not working with Fathom
---
[debug] Command-line config: ['-vU', 'https://fathom.video/share/TuBve9woubyxJ7zntDKmAYx9xj81WEnv']
[debug] Encodings: locale cp1252, fs utf-8, pref cp1252, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version stable@2023.10.13 [b634ba742] (win_exe)
[debug] Python 3.8.10 (CPython AMD64 64bit) - Windows-10-10.0.22631-SP0 (OpenSSL 1.1.1k  25 Mar 2021)
[debug] exe versions: ffmpeg 5.1-essentials_build-www.gyan.dev (setts), ffprobe 5.1-essentials_build-www.gyan.dev
[debug] Optional libraries: Cryptodome-3.19.0, brotli-1.1.0, certifi-2023.07.22, mutagen-1.47.0, sqlite3-3.35.5, websockets-11.0.3
[debug] Proxy map: {}
[debug] Loaded 1890 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Available version: stable@2023.12.30, Current version: stable@2023.10.13
Current Build Hash: 13d6a04ef6678dc61cb6e2d42eb53e69486bd2f52b8e5d778db029ccd4c600b4
[debug] Downloading _update_spec from https://github.com/yt-dlp/yt-dlp/releases/latest/download/_update_spec
Updating to stable@2023.12.30 ...
[debug] Downloading yt-dlp.exe from https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe
[debug] Downloading SHA2-256SUMS from https://github.com/yt-dlp/yt-dlp/releases/latest/download/SHA2-256SUMS
Updated yt-dlp to stable@2023.12.30
[debug] Restarting: yt-dlp.exe -vU "https://fathom.video/share/TuBve9woubyxJ7zntDKmAYx9xj81WEnv"
[debug] Command-line config: ['-vU', 'https://fathom.video/share/TuBve9woubyxJ7zntDKmAYx9xj81WEnv']
[debug] Encodings: locale cp1252, fs utf-8, pref cp1252, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version stable@2023.12.30 from yt-dlp/yt-dlp [f10589e34] (win_exe)
[debug] Python 3.8.10 (CPython AMD64 64bit) - Windows-10-10.0.22631-SP0 (OpenSSL 1.1.1k  25 Mar 2021)
[debug] exe versions: ffmpeg 5.1-essentials_build-www.gyan.dev (setts), ffprobe 5.1-essentials_build-www.gyan.dev
[debug] Optional libraries: Cryptodome-3.19.1, brotli-1.1.0, certifi-2023.11.17, mutagen-1.47.0, requests-2.31.0, sqlite3-3.35.5, urllib3-2.1.0, websockets-12.0
[debug] Proxy map: {}
[debug] Request Handlers: urllib, requests, websockets
[debug] Loaded 1798 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Latest version: stable@2023.12.30 from yt-dlp/yt-dlp
yt-dlp is up to date (stable@2023.12.30 from yt-dlp/yt-dlp)
[generic] Extracting URL: https://fathom.video/share/TuBve9woubyxJ7zntDKmAYx9xj81WEnv
[generic] TuBve9woubyxJ7zntDKmAYx9xj81WEnv: Downloading webpage
WARNING: [generic] Falling back on generic information extractor
[generic] TuBve9woubyxJ7zntDKmAYx9xj81WEnv: Extracting information
[debug] Looking for embeds
ERROR: Unsupported URL: https://fathom.video/share/TuBve9woubyxJ7zntDKmAYx9xj81WEnv
Traceback (most recent call last):
  File "yt_dlp\YoutubeDL.py", line 1587, in wrapper
  File "yt_dlp\YoutubeDL.py", line 1722, in __extract_info
  File "yt_dlp\extractor\common.py", line 718, in extract
  File "yt_dlp\extractor\generic.py", line 2531, in _real_extract
yt_dlp.utils.UnsupportedError: Unsupported URL: https://fathom.video/share/TuBve9woubyxJ7zntDKmAYx9xj81WEnv
Will make a PR

Resolving patch:
diff --git a/yt_dlp/extractor/_extractors.py b/yt_dlp/extractor/_extractors.py
--- a/yt_dlp/extractor/_extractors.py
+++ b/yt_dlp/extractor/_extractors.py
@@ -590,6 +590,7 @@
     FacebookReelIE,
     FacebookAdsIE,
 )
+from .fathom import FathomIE
 from .fancode import (
     FancodeVodIE,
     FancodeLiveIE
diff --git a/yt_dlp/extractor/fathom.py b/yt_dlp/extractor/fathom.py
new file mode 100644
--- /dev/null
+++ b/yt_dlp/extractor/fathom.py
@@ -0,0 +1,54 @@
+import json
+
+from .common import InfoExtractor
+from ..utils import (
+    extract_attributes,
+    float_or_none,
+    get_element_html_by_id,
+    parse_iso8601,
+)
+from ..utils.traversal import traverse_obj
+
+
+class FathomIE(InfoExtractor):
+    _VALID_URL = r'https?://(?:www\.)?fathom\.video/share/(?P<id>[^/?#&]+)'
+    _TESTS = [{
+        'url': 'https://fathom.video/share/G9mkjkspnohVVZ_L5nrsoPycyWcB8y7s',
+        'md5': '0decd5343b8f30ae268625e79a02b60f',
+        'info_dict': {
+            'id': '47200596',
+            'ext': 'mp4',
+            'title': 'eCom Inucbator - Coaching Session',
+            'duration': 8125.380507,
+            'timestamp': 1699048914,
+            'upload_date': '20231103',
+        },
+    }, {
+        'url': 'https://fathom.video/share/mEws3bybftHL2QLymxYEDeE21vtLxGVm',
+        'md5': '4f5cb382126c22d1aba8a939f9c49690',
+        'info_dict': {
+            'id': '46812957',
+            'ext': 'mp4',
+            'title': 'Jon, Lawrence, Neman chat about practice',
+            'duration': 3571.517847,
+            'timestamp': 1698933600,
+            'upload_date': '20231102',
+        },
+    }]
+
+    def _real_extract(self, url):
+        display_id = self._match_id(url)
+        webpage = self._download_webpage(url, display_id)
+        props = traverse_obj(
+            get_element_html_by_id('app', webpage), ({extract_attributes}, 'data-page', {json.loads}, 'props'))
+        video_id = str(props['call']['id'])
+
+        return {
+            'id': video_id,
+            'formats': self._extract_m3u8_formats(props['call']['video_url'], video_id, 'mp4'),
+            **traverse_obj(props, {
+                'title': ('head', 'title', {str}),
+                'duration': ('duration', {float_or_none}),
+                'timestamp': ('call', 'started_at', {parse_iso8601}),
+            }),
+        }


Test patch: