Repository: yt-dlp/yt-dlp

Issue:
add TVI player
### Checklist

- [X] I'm reporting a site feature request
- [X] I've verified that I'm running yt-dlp version **2021.12.27**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
- [X] I've checked that all provided URLs are alive and playable in a browser
- [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

Portugal

### Example URLs

https://tviplayer.iol.pt/programa/jornal-das-8/53c6b3903004dc006243d0cf/video/61c8e8b90cf2c7ea0f0f71a9

### Description

i suggest you add TVIplayer to extractors it's a portuguese open tv channel.
some contents are only accessible in portugal-

### Verbose log

```shell
no log
```



Discussion:
add proper log.
Fields are not for entertainment.
what log i have to add?
probably i posted in wrong place. but i just wanted to suggest adition to downloading videos from tvi player's site.
i aded a url to example.
From the template

> Provide the complete verbose output **using one of the example URLs provided above**.

This was added because we kept getting site requests for sites that were already supported!

```
➤ yt-dlp "https://tviplayer.iol.pt/programa/jornal-das-8/53c6b3903004dc006243d0cf/video/61c8e8b90cf2c7ea0f0f71a9"
[generic] 61c8e8b90cf2c7ea0f0f71a9: Requesting header
WARNING: [generic] Falling back on generic information extractor.
[generic] 61c8e8b90cf2c7ea0f0f71a9: Downloading webpage
[generic] 61c8e8b90cf2c7ea0f0f71a9: Extracting information
ERROR: Unsupported URL: https://tviplayer.iol.pt/programa/jornal-das-8/53c6b3903004dc006243d0cf/video/61c8e8b90cf2c7ea0f0f71a9
```



Issue still occurs with version 2022.06.29

```
yt-dlp -vU "https://tviplayer.iol.pt/programa/isabel/62b471090cf26256cd2a8594/video/62be445f0cf2ea4f0a5218e5"
[debug] Command-line config: ['-vU', 'https://tviplayer.iol.pt/programa/isabel/62b471090cf26256cd2a8594/video/62be445f0cf2ea4f0a5218e5']
[debug] Encodings: locale cp1252, fs utf-8, pref cp1252, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version 2022.06.29 [9d339c4] (win32_exe)
[debug] Python 3.8.10 (CPython 64bit) - Windows-10-10.0.19044-SP0
[debug] Checking exe version: ffmpeg -bsfs
[debug] Checking exe version: avconv -bsfs
[debug] Checking exe version: ffprobe -bsfs
[debug] Checking exe version: avprobe -bsfs
[debug] exe versions: none
[debug] Optional libraries: Cryptodome-3.15.0, brotli-1.0.9, certifi-2022.06.15, mutagen-1.45.1, sqlite3-2.6.0, websockets-10.3
[debug] Proxy map: {}
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
[debug] Downloading _update_spec from https://github.com/yt-dlp/yt-dlp/releases/download/2022.06.29/_update_spec
Latest version: 2022.06.29, Current version: 2022.06.29
yt-dlp is up to date (2022.06.29)
[debug] [generic] Extracting URL: https://tviplayer.iol.pt/programa/isabel/62b471090cf26256cd2a8594/video/62be445f0cf2ea4f0a5218e5
[generic] 62be445f0cf2ea4f0a5218e5: Requesting header
WARNING: [generic] Falling back on generic information extractor.
[generic] 62be445f0cf2ea4f0a5218e5: Downloading webpage
[generic] 62be445f0cf2ea4f0a5218e5: Extracting information
[debug] Looking for video embeds
ERROR: Unsupported URL: https://tviplayer.iol.pt/programa/isabel/62b471090cf26256cd2a8594/video/62be445f0cf2ea4f0a5218e5
Traceback (most recent call last):
  File "yt_dlp\YoutubeDL.py", line 1420, in wrapper
  File "yt_dlp\YoutubeDL.py", line 1490, in __extract_info
  File "yt_dlp\extractor\common.py", line 640, in extract
  File "yt_dlp\extractor\generic.py", line 4130, in _real_extract
yt_dlp.utils.UnsupportedError: Unsupported URL: https://tviplayer.iol.pt/programa/isabel/62b471090cf26256cd2a8594/video/62be445f0cf2ea4f0a5218e5
```
From OP link, i found the video in `script` tag that have `jsonData` variable,
Here's the `script` tag that i described:
```html
<script>
jsonData = {
	"duration": 4167,
	"cover": "https://www.iol.pt/multimedia/oratvi/multimedia/imagem/id/61c8ee630cf2cc58e7d98d9f/",
	"videoUrl": "https://streaming-vod3.iol.pt/vod/_definst_/7/1/a/9/smil:61c8e8b90cf2c7ea0f0f71a9-L/playlist.m3u8",
	"videoType": "Integra",
	"liveType": "VOD",
	"description": "<p>Com José Alberto Carvalho<\/p>",
	"id": "61c8e8b90cf2c7ea0f0f71a9",
	"program": {
		"name": "Jornal das 8",
		"epNum": "Sem Episódio",
		"season": "5fec9ae70cf28e704d9f883b",
		"id": "53c6b3903004dc006243d0cf",
		"ep": "Sem Episódio",
		"seasonNum": 8
	},
	"title": "Jornal das 8 - 26 de dezembro de 2021"
};
head.ready(function() {
	var pub = '/130294768/tviplayer/web/jornaldas8/video/VIDEO';
	var pub_patrocinado = false ? "" : pub;
	$('#player').iolplayer({
		video: [jsonData],
		pub: pub_patrocinado,
		smartToken: "A12FFAZ7B226964436F6E746575646F223A2022363143384538423930434632433745413046304637314139222C227469706F436F6E746575646F223A2022766964656F222C22706C617461666F726D61223A2022776562222C226F726967656D223A2022747669706C61796572222C2270726F6772616D61223A20226A6F726E616C64617338222C22696455736572223A2022227D",
		autostart: false,
		project: "tviplayer",
		pageContentType: "VIDEO",
		videoRedirect: true,
		"skin": {
			"timeslider": {
				"progress": "#fab432"
			}
		}
	});
});
</script>
```
The url need query parameter `wmsAuthSign`. We can get that parameter with request to `https://services.iol.pt/matrix?userId=` with `GET` method. The final url should be like `<jsonData['videoUrl']>?wmsAuthSign=<wmsAuthSign>` 

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
@@ -1823,6 +1823,7 @@
 )
 from .tver import TVerIE
 from .tvigle import TvigleIE
+from .tviplayer import TVIPlayerIE
 from .tvland import TVLandIE
 from .tvn24 import TVN24IE
 from .tvnet import TVNetIE
diff --git a/yt_dlp/extractor/tviplayer.py b/yt_dlp/extractor/tviplayer.py
new file mode 100644
--- /dev/null
+++ b/yt_dlp/extractor/tviplayer.py
@@ -0,0 +1,65 @@
+from .common import InfoExtractor
+from ..utils import traverse_obj
+
+
+class TVIPlayerIE(InfoExtractor):
+    _VALID_URL = r'https?://tviplayer\.iol\.pt(/programa/[\w-]+/[a-f0-9]+)?/video/(?P<id>[a-f0-9]+)'
+    _TESTS = [{
+        'url': 'https://tviplayer.iol.pt/programa/jornal-das-8/53c6b3903004dc006243d0cf/video/61c8e8b90cf2c7ea0f0f71a9',
+        'info_dict': {
+            'id': '61c8e8b90cf2c7ea0f0f71a9',
+            'ext': 'mp4',
+            'duration': 4167,
+            'title': 'Jornal das 8 - 26 de dezembro de 2021',
+            'thumbnail': 'https://www.iol.pt/multimedia/oratvi/multimedia/imagem/id/61c8ee630cf2cc58e7d98d9f/',
+            'season_number': 8,
+            'season': 'Season 8',
+        }
+    }, {
+        'url': 'https://tviplayer.iol.pt/programa/isabel/62b471090cf26256cd2a8594/video/62be445f0cf2ea4f0a5218e5',
+        'info_dict': {
+            'id': '62be445f0cf2ea4f0a5218e5',
+            'ext': 'mp4',
+            'duration': 3255,
+            'season': 'Season 1',
+            'title': 'Isabel - Episódio 1',
+            'thumbnail': 'https://www.iol.pt/multimedia/oratvi/multimedia/imagem/id/62beac200cf2f9a86eab856b/',
+            'season_number': 1,
+        }
+    }, {
+        'url': 'https://tviplayer.iol.pt/video/62c4131c0cf2f9a86eac06bb',
+        'info_dict': {
+            'id': '62c4131c0cf2f9a86eac06bb',
+            'ext': 'mp4',
+            'title': 'David e Mickael Carreira respondem: «Qual é o próximo a ser pai?»',
+            'thumbnail': 'https://www.iol.pt/multimedia/oratvi/multimedia/imagem/id/62c416490cf2ea367d4433fd/',
+            'season': 'Season 2',
+            'duration': 148,
+            'season_number': 2,
+        }
+    }]
+
+    def _real_initialize(self):
+        self.wms_auth_sign_token = self._download_webpage(
+            'https://services.iol.pt/matrix?userId=', 'wmsAuthSign',
+            note='Trying to get wmsAuthSign token')
+
+    def _real_extract(self, url):
+        video_id = self._match_id(url)
+        webpage = self._download_webpage(url, video_id)
+
+        json_data = self._search_json(
+            r'<script>\s*jsonData\s*=\s*', webpage, 'json_data', video_id)
+
+        formats, subtitles = self._extract_m3u8_formats_and_subtitles(
+            f'{json_data["videoUrl"]}?wmsAuthSign={self.wms_auth_sign_token}',
+            video_id, ext='mp4')
+        return {
+            'id': video_id,
+            'title': json_data.get('title') or self._og_search_title(webpage),
+            'thumbnail': json_data.get('cover') or self._og_search_thumbnail(webpage),
+            'duration': json_data.get('duration'),
+            'formats': formats,
+            'subtitles': subtitles,
+            'season_number': traverse_obj(json_data, ('program', 'seasonNum')),
+        }


Test patch: