Repository: streamlink/streamlink

Issue:
plugins.showroom: streamlink recording a different showroom stream than the one specified
### Checklist

- [X] This is a plugin issue and not a different kind of issue
- [X] [I have read the contribution guidelines](https://github.com/streamlink/streamlink/blob/master/CONTRIBUTING.md#contributing-to-streamlink)
- [X] [I have checked the list of open and recently closed plugin issues](https://github.com/streamlink/streamlink/issues?q=is%3Aissue+label%3A%22plugin+issue%22)
- [x] [I have checked the commit log of the master branch](https://github.com/streamlink/streamlink/commits/master)

### Streamlink version

Latest stable release

### Description

Recently showroom.com has made some changes to their site.

When I try to use streamlink to record a showroom url that is offline, for eg. https://www.showroom-live.com/r/46_ikedateresa

> streamlink --loglevel debug https://www.showroom-live.com/r/46_ikedateresa best -o testing.ts`

the expected behavior is that it should return this:

> This stream is currently offline
error: No playable streams found on this URL: https://www.showroom-live.com/r/46_ikedateresa`


However, when I tried entering the above command 40-50 times in a row (tried both manually and using a .bat file), streamlink started recording a random different Showroom stream that is currently online. If I close streamlink and repeat the entire process again, it will record another random online stream.

This outcome only happened since a few days ago.

I have been using a bat script (since 2017) to get streamlink to keep repeating the same command every few seconds until the showroom stream turns online, so that I can record the stream when I am away. But now with the changes made, streamlink will be led to recording a different stream, so when the original stream that it is supposed to record begins, it won't record that anymore. 


Bat script I use:

```bat
@echo off

::set _task=notepad.exe
set _task=streamlink

goto CHECK

:CHECK
REM  Check whether the process is running 
qprocess  >tasklist_tmp.txt

type tasklist_tmp.txt | findstr /i %_task%
  
if %errorlevel% ==0  goto SLEEP

if %errorlevel% ==1  goto RUN

:RUN

set _suffix=.ts
set _command=streamlink --loglevel debug --stream-segment-threads 10 --stream-segment-timeout 15.0 --stream-segment-attempts 12 --hls-live-edge 2 --ringbuffer-size 900M --hls-playlist-reload-attempts 10 https://www.showroom-live.com/46_SHIHO_KATO best -o 
::set _current_time=%date:~0,4%%date:~5,2%%date:~8,2%-%time:~0,2%%time:~3,2%%time:~6,2% 
::set _service=%_command%%_current_time%%_suffix%

rem echo Get current date
for /f "tokens=1,2,3 delims=/- " %%a in ("%date%") do @set D=%%a%%b%%c
rem echo Get current time
for /f "tokens=1,2,3 delims=:." %%a in ("%time%") do @set T=%%a%%b%%c
rem echo If current hour less than 10£¬add 0 before hour
set T=%T: =0%
rem echo display current date and time
echo %D%%T%

set _service=%_command%L:\46_ikedateresa-%D%%T%%_suffix%

echo %_service%
::start c:\windows\system32\notepad.exe
start %_service%
echo The program started at %time%>>deamon.log

:SLEEP
REM  sleep for 10 minutes
echo %time% The Program is Running,sleep for 5s...
echo Wscript.Sleep WScript.Arguments(0) >%tmp%\delay.vbs 
cscript //b //nologo %tmp%\delay.vbs 3000

goto CHECK
```


### Debug log

```text
Expected result when recording a showroom stream that is yet to start: 

L:\>streamlink --loglevel debug https://www.showroom-live.com/r/46_ikedateresa best -o testing1.ts
[cli][debug] OS:         Windows 10
[cli][debug] Python:     3.10.6
[cli][debug] Streamlink: 5.5.1
[cli][debug] Dependencies:
[cli][debug]  certifi: 2022.6.15
[cli][debug]  isodate: 0.6.1
[cli][debug]  lxml: 4.9.1
[cli][debug]  pycountry: 22.3.5
[cli][debug]  pycryptodome: 3.16.0
[cli][debug]  PySocks: 1.7.1
[cli][debug]  requests: 2.28.2
[cli][debug]  urllib3: 1.26.12
[cli][debug]  websocket-client: 1.4.0
[cli][debug] Arguments:
[cli][debug]  url=https://www.showroom-live.com/r/46_ikedateresa
[cli][debug]  stream=['best']
[cli][debug]  --loglevel=debug
[cli][debug]  --output=testing1.ts
[cli][info] Found matching plugin showroom for URL https://www.showroom-live.com/r/46_ikedateresa
[plugins.showroom][info] This stream is currently offline
error: No playable streams found on this URL: https://www.showroom-live.com/r/46_ikedateresa

---------------------------------------------------------------------------------------------------

Unexpected result after 40-50 attempts: streamlink starts recording a different showroom stream (the stream that it is supposed to record have yet to start)

L:\>streamlink --loglevel debug https://www.showroom-live.com/r/46_ikedateresa best -o testing1.ts
[cli][debug] OS:         Windows 10
[cli][debug] Python:     3.10.6
[cli][debug] Streamlink: 5.5.1
[cli][debug] Dependencies:
[cli][debug]  certifi: 2022.6.15
[cli][debug]  isodate: 0.6.1
[cli][debug]  lxml: 4.9.1
[cli][debug]  pycountry: 22.3.5
[cli][debug]  pycryptodome: 3.16.0
[cli][debug]  PySocks: 1.7.1
[cli][debug]  requests: 2.28.2
[cli][debug]  urllib3: 1.26.12
[cli][debug]  websocket-client: 1.4.0
[cli][debug] Arguments:
[cli][debug]  url=https://www.showroom-live.com/r/46_ikedateresa
[cli][debug]  stream=['best']
[cli][debug]  --loglevel=debug
[cli][debug]  --output=testing1.ts
[cli][info] Found matching plugin showroom for URL https://www.showroom-live.com/r/46_ikedateresa
[utils.l10n][debug] Language code: en_US
[cli][info] Available streams: 144p (worst), 360p, 720p (best)
[cli][info] Opening stream: 720p (hls)
[cli][info] Writing output to
L:\testing1.ts
[cli][debug] Checking file output
[stream.hls][debug] Reloading playlist
[cli][debug] Pre-buffering 8192 bytes
[stream.hls][debug] First Sequence: 32034; Last Sequence: 32038
[stream.hls][debug] Start offset: 0; Duration: None; Start Sequence: 32036; End Sequence: None
[stream.hls][debug] Adding segment 32036 to queue
[stream.hls][debug] Adding segment 32037 to queue
[stream.hls][debug] Adding segment 32038 to queue
[stream.hls][debug] Writing segment 32036 to output
[stream.hls][debug] Segment 32036 complete
[cli][debug] Writing stream to output
[download] Written 419.51 KiB to testing1.ts (0s)                                                                      [stream.hls][debug] Writing segment 32037 to output
[stream.hls][debug] Segment 32037 complete
[download] Written 875.55 KiB to testing1.ts (0s)                                                                      [stream.hls][debug] Writing segment 32038 to output
[stream.hls][debug] Segment 32038 complete
[stream.hls][debug] Reloading playlist
[download] Written 1.26 MiB to testing1.ts (1s)                                                                        [stream.hls][debug] Adding segment 32039 to queue
[download] Written 1.26 MiB to testing1.ts (1s)                                                                        [stream.hls][debug] Writing segment 32039 to output
[stream.hls][debug] Segment 32039 complete
[download] Written 1.65 MiB to testing1.ts (2s @ 672.65 KiB/s)                                                         [stream.hls][debug] Reloading playlist
[download] Written 1.65 MiB to testing1.ts (3s @ 611.75 KiB/s)                                                         [stream.hls][debug] Adding segment 32040 to queue
[download] Written 1.65 MiB to testing1.ts (3s @ 560.78 KiB/s)                                                         [stream.hls][debug] Writing segment 32040 to output
[stream.hls][debug] Segment 32040 complete
[download] Written 2.03 MiB to testing1.ts (4s @ 458.55 KiB/s)                                                         [stream.hls][debug] Reloading playlist
[stream.hls][debug] Adding segment 32041 to queue
```



Discussion:
Here's the plugin code:
https://github.com/streamlink/streamlink/blob/5.5.1/src/streamlink/plugins/showroom.py

What you describe suggests that an incorrect room ID gets found when the channel is offline. The actual HLS stream URL is retrieved from their API which requires a specific room ID as one of the parameters, and it also checks for the online status first using the room ID.

The room ID currently gets extracted from some `share_url` object property in one of their embedded JS scripts, so this is probably not the right solution.

Resolving patch:
diff --git a/src/streamlink/plugins/showroom.py b/src/streamlink/plugins/showroom.py
--- a/src/streamlink/plugins/showroom.py
+++ b/src/streamlink/plugins/showroom.py
@@ -6,6 +6,7 @@
 
 import logging
 import re
+from urllib.parse import parse_qsl, urlparse
 
 from streamlink.plugin import Plugin, pluginmatcher
 from streamlink.plugin.api import validate
@@ -30,16 +31,18 @@ def _get_streams(self):
             self.url,
             schema=validate.Schema(
                 validate.parse_html(),
-                validate.xml_xpath_string(".//script[contains(text(),'share_url:\"https:')][1]/text()"),
+                validate.xml_xpath_string(".//nav//a[contains(@href,'/room/profile?')]/@href"),
                 validate.none_or_all(
-                    re.compile(r"share_url:\"https:[^?]+?\?room_id=(?P<room_id>\d+)\""),
-                    validate.any(None, validate.get("room_id")),
+                    validate.transform(lambda _url_profile: dict(parse_qsl(urlparse(_url_profile).query))),
+                    validate.get("room_id"),
                 ),
             ),
         )
         if not room_id:
             return
 
+        log.debug(f"Room ID: {room_id}")
+
         live_status, self.title = self.session.http.get(
             "https://www.showroom-live.com/api/live/live_info",
             params={


Test patch: