Repository: yt-dlp/yt-dlp

Issue:
Support https://www.lumni.fr
### DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE

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

### Checklist

- [X] I'm requesting a site-specific feature
- [X] I've verified that I'm running yt-dlp version **2023.01.06** ([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 searched 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 I'm willing to share it if required

### Region

France

### Example URLs

https://www.lumni.fr/video/l-homme-et-son-environnement-dans-la-revolution-industrielle

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

The "lumni" website is from France Télévisions. They used the same video player and distribution system from their main website france.tv.

I was able to download the video by grabbing the data-factoryid, for example `d2b9a4e5-a526-495b-866c-ab72737e3645` (from the source code) for this video: https://www.lumni.fr/video/l-homme-et-son-environnement-dans-la-revolution-industrielle .

Then I used yt-dlp with the francetv downloading plugin:
`yt-dlp francetv:d2b9a4e5-a526-495b-866c-ab72737e3645`

So I guess this issue could be fixed by adding the lumni.fr URLs to the francetv URL sheme.

### 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] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below

### Complete Verbose Output

```shell
[debug] Command-line config: ['-vU', 'https://www.lumni.fr/video/l-homme-et-son-environnement-dans-la-revolution-industrielle']
[debug] Encodings: locale UTF-8, fs utf-8, pref UTF-8, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version 2023.01.06 [6becd25]
[debug] Python 3.10.9 (CPython x86_64 64bit) - Linux-6.1.9-arch1-2-x86_64-with-glibc2.37 (OpenSSL 3.0.8 7 Feb 2023, glibc 2.37)
[debug] exe versions: ffmpeg 5.1.2 (setts), ffprobe 5.1.2, rtmpdump 2.4
[debug] Optional libraries: Cryptodome-3.12.0, brotlicffi-1.0.9.2, certifi-2022.12.07, mutagen-1.46.0, secretstorage-3.3.3, sqlite3-2.6.0
[debug] Proxy map: {}
[debug] Loaded 1760 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Latest version: 2023.01.06, Current version: 2023.01.06
yt-dlp is up to date (2023.01.06)
[generic] Extracting URL: https://www.lumni.fr/video/l-homme-et-son-environnement-dans-la-revolution-industrielle
[generic] l-homme-et-son-environnement-dans-la-revolution-industrielle: Downloading webpage
WARNING: [generic] Falling back on generic information extractor
[generic] l-homme-et-son-environnement-dans-la-revolution-industrielle: Extracting information
[debug] Looking for embeds
ERROR: Unsupported URL: https://www.lumni.fr/video/l-homme-et-son-environnement-dans-la-revolution-industrielle
Traceback (most recent call last):
  File "/usr/lib/python3.10/site-packages/yt_dlp/YoutubeDL.py", line 1502, in wrapper
    return func(self, *args, **kwargs)
  File "/usr/lib/python3.10/site-packages/yt_dlp/YoutubeDL.py", line 1578, in __extract_info
    ie_result = ie.extract(url)
  File "/usr/lib/python3.10/site-packages/yt_dlp/extractor/common.py", line 680, in extract
    ie_result = self._real_extract(url)
  File "/usr/lib/python3.10/site-packages/yt_dlp/extractor/generic.py", line 2523, in _real_extract
    raise UnsupportedError(url)
yt_dlp.utils.UnsupportedError: Unsupported URL: https://www.lumni.fr/video/l-homme-et-son-environnement-dans-la-revolution-industrielle
```



Discussion:
> So I guess this issue could be fixed by adding the lumni.fr URLs to the francetv URL sheme.

No, because the video id is not in the URL. An extractor has to be written to extract and forward it to FranceTVIE

---

For devs:

The video id is in
```html
<div class="player" id="player" data-factoryid="d2b9a4e5-a526-495b-866c-ab72737e3645"
```
The extractor can then just return `self.url_result(f'francetv:{video_id}', FranceTVIE, video_id)`

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
@@ -962,6 +962,9 @@
     LRTVODIE,
     LRTStreamIE
 )
+from .lumni import (
+    LumniIE
+)
 from .lynda import (
     LyndaIE,
     LyndaCourseIE
diff --git a/yt_dlp/extractor/lumni.py b/yt_dlp/extractor/lumni.py
new file mode 100644
--- /dev/null
+++ b/yt_dlp/extractor/lumni.py
@@ -0,0 +1,24 @@
+from .common import InfoExtractor
+from .francetv import FranceTVIE
+
+
+class LumniIE(InfoExtractor):
+    _VALID_URL = r'https?://(?:www\.)?lumni\.fr/video/(?P<id>[\w-]+)'
+    _TESTS = [{
+        'url': 'https://www.lumni.fr/video/l-homme-et-son-environnement-dans-la-revolution-industrielle',
+        'md5': '960e8240c4f2c7a20854503a71e52f5e',
+        'info_dict': {
+            'id': 'd2b9a4e5-a526-495b-866c-ab72737e3645',
+            'ext': 'mp4',
+            'title': "L'homme et son environnement dans la révolution industrielle - L'ère de l'homme",
+            'thumbnail': 'https://assets.webservices.francetelevisions.fr/v1/assets/images/a7/17/9f/a7179f5f-63a5-4e11-8d4d-012ab942d905.jpg',
+            'duration': 230,
+        }
+    }]
+
+    def _real_extract(self, url):
+        display_id = self._match_id(url)
+        webpage = self._download_webpage(url, display_id)
+        video_id = self._html_search_regex(
+            r'<div[^>]+data-factoryid\s*=\s*["\']([^"\']+)', webpage, 'video id')
+        return self.url_result(f'francetv:{video_id}', FranceTVIE, video_id)


Test patch: