[CORE] Remove some key from json

This commit is contained in:
Dark1291 2025-02-26 09:54:36 +01:00
parent 9fe46cad39
commit 6a021de31f
12 changed files with 194 additions and 150 deletions

218
README.md
View File

@ -268,13 +268,39 @@ The configuration file is divided into several main sections:
```json ```json
{ {
"DEFAULT": {
"debug": false,
"show_message": true,
"clean_console": true,
"show_trending": true,
"use_api": true,
"not_close": false,
"telegram_bot": false
}
}
```
- `debug`: Enables debug logging
- `show_message`: Displays informational messages
- `clean_console`: Clears the console between operations
- `show_trending`: Shows trending content
- `use_api`: Uses API for domain updates instead of local configuration
- `not_close`: If set to true, keeps the program running after download is complete
* Can be changed from terminal with `--not_close true/false`
- `telegram_bot`: Enables Telegram bot integration
## OUT_FOLDER Settings
```json
{
"OUT_FOLDER": {
"root_path": "Video", "root_path": "Video",
"movie_folder_name": "Movie", "movie_folder_name": "Movie",
"serie_folder_name": "TV", "serie_folder_name": "Serie",
"map_episode_name": "%(tv_name)_S%(season)E%(episode)_%(episode_name)", "anime_folder_name": "Anime",
"add_siteName": false, "map_episode_name": "E%(episode)_%(episode_name)",
"disable_searchDomain": false, "add_siteName": false
"not_close": false }
} }
``` ```
@ -283,17 +309,21 @@ The configuration file is divided into several main sections:
### Path examples: ### Path examples:
* Windows: `C:\\MyLibrary\\Folder` or `\\\\MyServer\\MyLibrary` (if you want to use a network folder) * Windows: `C:\\MyLibrary\\Folder` or `\\\\MyServer\\MyLibrary` (if you want to use a network folder)
* Linux/MacOS: `Desktop/MyLibrary/Folder` * Linux/MacOS: `Desktop/MyLibrary/Folder`
`<br/><br/>` <br/><br/>
- `movie_folder_name`: The name of the subdirectory where movies will be stored. - `movie_folder_name`: The name of the subdirectory where movies will be stored
* Can be changed from terminal with `--movie_folder_name` * Can be changed from terminal with `--movie_folder_name`
<br/><br/> <br/><br/>
- `serie_folder_name`: The name of the subdirectory where TV series will be stored. - `serie_folder_name`: The name of the subdirectory where TV series will be stored
* Can be changed from terminal with `--serie_folder_name` * Can be changed from terminal with `--serie_folder_name`
<br/><br/> <br/><br/>
- `map_episode_name`: Template for TV series episode filenames - `anime_folder_name`: The name of the subdirectory where anime will be stored
* Can be changed from terminal with `--anime_folder_name`
<br/><br/>
- `map_episode_name`: Template for episode filenames
### Episode name usage: ### Episode name usage:
@ -302,29 +332,20 @@ The configuration file is divided into several main sections:
* `%(season)` : Is the number of the season * `%(season)` : Is the number of the season
* `%(episode)` : Is the number of the episode * `%(episode)` : Is the number of the episode
* `%(episode_name)` : Is the name of the episode * `%(episode_name)` : Is the name of the episode
`<br/><br/>`
* Can be changed from terminal with `--map_episode_name` * Can be changed from terminal with `--map_episode_name`
<br/><br/> <br><br>
- `add_siteName`: If set to true, appends the site_name to the root path before the movie and serie folders. - `add_siteName`: If set to true, appends the site_name to the root path before the movie and serie folders
* Can be changed from terminal with `--add_siteName true/false` * Can be changed from terminal with `--add_siteName true/false`
<br/><br/> <br/><br/>
- `disable_searchDomain`: If set to true, disables the search for a new domain for all sites. ## QBIT_CONFIG Settings
* Can be changed from terminal with `--disable_searchDomain true/false`
<br/><br/>
- `not_close`: If set to true, keeps the program running after the download is complete.
* Can be changed from terminal with `--not_close true/false`
<br/><br/>
### qBittorrent Configuration
```json ```json
{ {
"config_qbit_tor": { "QBIT_CONFIG": {
"host": "192.168.1.59", "host": "192.168.1.51",
"port": "8080", "port": "6666",
"user": "admin", "user": "admin",
"pass": "adminadmin" "pass": "adminadmin"
} }
@ -333,29 +354,45 @@ The configuration file is divided into several main sections:
To enable qBittorrent integration, follow the setup guide [here](https://github.com/lgallard/qBittorrent-Controller/wiki/How-to-enable-the-qBittorrent-Web-UI). To enable qBittorrent integration, follow the setup guide [here](https://github.com/lgallard/qBittorrent-Controller/wiki/How-to-enable-the-qBittorrent-Web-UI).
## REQUESTS Settings ## REQUESTS Settings
```json ```json
{ {
"REQUESTS": {
"verify": false,
"timeout": 20, "timeout": 20,
"max_retry": 3 "max_retry": 8
}
} }
``` ```
- `verify`: Verifies SSL certificates
- `timeout`: Maximum timeout (in seconds) for each request - `timeout`: Maximum timeout (in seconds) for each request
- `max_retry`: Number of retry attempts per segment during M3U8 index download - `max_retry`: Number of retry attempts per segment during M3U8 index download
## M3U8_DOWNLOAD Settings ## M3U8_DOWNLOAD Settings
```json ```json
{ {
"M3U8_DOWNLOAD": {
"tqdm_delay": 0.01, "tqdm_delay": 0.01,
"default_video_workser": 12, "default_video_workser": 12,
"default_audio_workser": 12, "default_audio_workser": 12,
"segment_timeout": 8,
"download_audio": true,
"merge_audio": true,
"specific_list_audio": [
"ita"
],
"download_subtitle": true,
"merge_subs": true,
"specific_list_subtitles": [
"ita",
"eng"
],
"cleanup_tmp_folder": true "cleanup_tmp_folder": true
} }
}
``` ```
- `tqdm_delay`: Delay between progress bar updates - `tqdm_delay`: Delay between progress bar updates
@ -367,67 +404,89 @@ The configuration file is divided into several main sections:
* Can be changed from terminal with `--default_audio_worker <number>` * Can be changed from terminal with `--default_audio_worker <number>`
<br/><br/> <br/><br/>
- `segment_timeout`: Timeout for downloading individual segments
- `download_audio`: Whether to download audio tracks
- `merge_audio`: Whether to merge audio with video
- `specific_list_audio`: List of audio languages to download
* Can be changed from terminal with `--specific_list_audio ita,eng`
<br/><br/>
- `download_subtitle`: Whether to download subtitles
- `merge_subs`: Whether to merge subtitles with video
- `specific_list_subtitles`: List of subtitle languages to download
* Can be changed from terminal with `--specific_list_subtitles ita,eng`
<br/><br/>
- `cleanup_tmp_folder`: Remove temporary .ts files after download - `cleanup_tmp_folder`: Remove temporary .ts files after download
## Available Language Codes
| European | Asian | Middle Eastern | Others |
|-----------------|-----------------|-----------------|-----------------|
| ita - Italian | chi - Chinese | ara - Arabic | eng - English |
| spa - Spanish | jpn - Japanese | heb - Hebrew | por - Portuguese|
| fre - French | kor - Korean | tur - Turkish | fil - Filipino |
| ger - German | hin - Hindi | | ind - Indonesian|
| rus - Russian | mal - Malayalam | | may - Malay |
| swe - Swedish | tam - Tamil | | vie - Vietnamese|
| pol - Polish | tel - Telugu | | |
| ukr - Ukrainian | tha - Thai | | |
### Language Settings ## M3U8_CONVERSION Settings
The following codes can be used for `specific_list_audio` and `specific_list_subtitles`: ```json
* Can be changed from terminal with `--specific_list_audio ita,eng` for audio {
* Can be changed from terminal with `--specific_list_subtitles eng,spa` for subtitles "M3U8_CONVERSION": {
"use_codec": false,
"use_vcodec": true,
``` "use_acodec": true,
ara - Arabic eng - English ita - Italian por - Portuguese "use_bitrate": true,
baq - Basque fil - Filipino jpn - Japanese rum - Romanian "use_gpu": false,
cat - Catalan fin - Finnish kan - Kannada rus - Russian "default_preset": "ultrafast"
chi - Chinese fre - French kor - Korean spa - Spanish }
cze - Czech ger - German mal - Malayalam swe - Swedish }
dan - Danish glg - Galician may - Malay tam - Tamil
dut - Dutch gre - Greek nob - Norw. Bokm tel - Telugu
heb - Hebrew nor - Norwegian tha - Thai
forced-ita hin - Hindi pol - Polish tur - Turkish
hun - Hungarian ukr - Ukrainian
ind - Indonesian vie - Vietnamese
``` ```
> [!NOTE] - `use_codec`: Use specific codec settings
> When using subtitles on Windows, please note that the default Windows Media Player may not display them correctly. We recommend using VLC Media Player for proper subtitle display and optimal playback experience. - `use_vcodec`: Use specific video codec
- `use_acodec`: Use specific audio codec
- `use_bitrate`: Apply bitrate settings
- `use_gpu`: Enable GPU acceleration (if available)
- `default_preset`: FFmpeg encoding preset (ultrafast, fast, medium, slow, etc.)
### Advanced M3U8 Conversion Options
> [!IMPORTANT] The software supports various advanced encoding options via FFmpeg:
> Language code availability may vary by site. Some platforms might:
>
> - Use different language codes
> - Support only a subset of these languages
> - Offer additional languages not listed here
>
> Check the specific site's available options if downloads fail.
> [!TIP] #### Encoding Presets
> You can configure multiple languages by adding them to the lists: The `default_preset` configuration can be set to one of the following values:
> - `ultrafast`: Extremely fast conversion but larger file size
> ```json - `superfast`: Very fast with good quality/size ratio
> "specific_list_audio": ["ita", "eng", "spa"], - `veryfast`: Fast with good compression
> "specific_list_subtitles": ["ita", "eng", "spa"] - `faster`: Optimal balance for most users
> ``` - `fast`: Good compression, moderate time
- `medium`: FFmpeg default setting
- `slow`: High quality, slower process
- `slower`: Very high quality, slow process
- `veryslow`: Maximum quality, very slow process
For the best viewing experience, we recommend using VLC Media Player: #### GPU Acceleration
- Supports all video formats and codecs When `use_gpu` is enabled, the system will use available hardware acceleration:
- Properly displays embedded subtitles - NVIDIA: NVENC
- Available for all major operating systems - AMD: AMF
- Free and open-source - Intel: QSV
You can download VLC Media Player from the [official website](https://www.videolan.org/vlc/). You need to have updated drivers and FFmpeg compiled with hardware acceleration support.
## M3U8_PARSER Settings ## M3U8_PARSER Settings
```json ```json
{ {
"force_resolution": "1080p", "M3U8_PARSER": {
"force_resolution": "Best",
"get_only_link": false "get_only_link": false
} }
}
``` ```
- `force_resolution`: Choose the video resolution for downloading: - `force_resolution`: Choose the video resolution for downloading:
@ -446,6 +505,24 @@ You can download VLC Media Player from the [official website](https://www.videol
- `get_only_link`: Return M3U8 playlist/index URL instead of downloading - `get_only_link`: Return M3U8 playlist/index URL instead of downloading
## SITE_EXTRA Settings
```json
{
"SITE_EXTRA": {
"ddlstreamitaly": {
"ips4_device_key": "",
"ips4_member_id": "",
"ips4_login_key": ""
}
}
}
```
- Site-specific configuration for `ddlstreamitaly`:
- `ips4_device_key`: Device key for authentication
- `ips4_member_id`: Member ID for authentication
- `ips4_login_key`: Login key for authentication
## Update Domains ## Update Domains
@ -506,9 +583,6 @@ python test_run.py --specific_list_audio ita,eng --specific_list_subtitles eng,s
# Keep console open after download # Keep console open after download
python test_run.py --not_close true python test_run.py --not_close true
# Disable domain search and add site name
python test_run.py --disable_searchDomain true --add_siteName true
``` ```
# Docker # Docker

View File

@ -24,7 +24,6 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
media_search_manager = MediaManager() media_search_manager = MediaManager()
table_show_manager = TVShowManager() table_show_manager = TVShowManager()
max_timeout = config_manager.get_int("REQUESTS", "timeout") max_timeout = config_manager.get_int("REQUESTS", "timeout")
disable_searchDomain = config_manager.get_bool("DEFAULT", "disable_searchDomain")
def title_search(word_to_search: str) -> int: def title_search(word_to_search: str) -> int:
@ -40,10 +39,7 @@ def title_search(word_to_search: str) -> int:
media_search_manager.clear() media_search_manager.clear()
table_show_manager.clear() table_show_manager.clear()
# Find new domain if prev dont work # Check if domain is working
domain_to_use = site_constant.DOMAIN_NOW
if not disable_searchDomain:
domain_to_use, base_url = search_domain(site_constant.SITE_NAME, site_constant.FULL_URL) domain_to_use, base_url = search_domain(site_constant.SITE_NAME, site_constant.FULL_URL)
if domain_to_use is None or base_url is None: if domain_to_use is None or base_url is None:

View File

@ -26,7 +26,6 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
media_search_manager = MediaManager() media_search_manager = MediaManager()
table_show_manager = TVShowManager() table_show_manager = TVShowManager()
max_timeout = config_manager.get_int("REQUESTS", "timeout") max_timeout = config_manager.get_int("REQUESTS", "timeout")
disable_searchDomain = config_manager.get_bool("DEFAULT", "disable_searchDomain")
def get_token(site_name: str, domain: str) -> dict: def get_token(site_name: str, domain: str) -> dict:
@ -110,10 +109,7 @@ def title_search(title: str) -> int:
media_search_manager.clear() media_search_manager.clear()
table_show_manager.clear() table_show_manager.clear()
# Get token and session value from configuration # Check if domain is working
domain_to_use = site_constant.DOMAIN_NOW
if not disable_searchDomain:
domain_to_use, base_url = search_domain(site_constant.SITE_NAME, site_constant.FULL_URL) domain_to_use, base_url = search_domain(site_constant.SITE_NAME, site_constant.FULL_URL)
if domain_to_use is None or base_url is None: if domain_to_use is None or base_url is None:

View File

@ -24,7 +24,6 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
media_search_manager = MediaManager() media_search_manager = MediaManager()
table_show_manager = TVShowManager() table_show_manager = TVShowManager()
max_timeout = config_manager.get_int("REQUESTS", "timeout") max_timeout = config_manager.get_int("REQUESTS", "timeout")
disable_searchDomain = config_manager.get_bool("DEFAULT", "disable_searchDomain")
def title_search(word_to_search: str) -> int: def title_search(word_to_search: str) -> int:
@ -40,10 +39,7 @@ def title_search(word_to_search: str) -> int:
media_search_manager.clear() media_search_manager.clear()
table_show_manager.clear() table_show_manager.clear()
# Find new domain if prev dont work # Check if domain is working
domain_to_use = site_constant.DOMAIN_NOW
if not disable_searchDomain:
domain_to_use, base_url = search_domain(site_constant.SITE_NAME, site_constant.FULL_URL) domain_to_use, base_url = search_domain(site_constant.SITE_NAME, site_constant.FULL_URL)
if domain_to_use is None or base_url is None: if domain_to_use is None or base_url is None:

View File

@ -26,7 +26,6 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
media_search_manager = MediaManager() media_search_manager = MediaManager()
table_show_manager = TVShowManager() table_show_manager = TVShowManager()
max_timeout = config_manager.get_int("REQUESTS", "timeout") max_timeout = config_manager.get_int("REQUESTS", "timeout")
disable_searchDomain = config_manager.get_bool("DEFAULT", "disable_searchDomain")
def title_search(word_to_search: str) -> int: def title_search(word_to_search: str) -> int:
@ -42,10 +41,7 @@ def title_search(word_to_search: str) -> int:
media_search_manager.clear() media_search_manager.clear()
table_show_manager.clear() table_show_manager.clear()
# Find new domain if prev dont work # Check if domain is working
domain_to_use = site_constant.DOMAIN_NOW
if not disable_searchDomain:
domain_to_use, base_url = search_domain(site_constant.SITE_NAME, site_constant.FULL_URL) domain_to_use, base_url = search_domain(site_constant.SITE_NAME, site_constant.FULL_URL)
if domain_to_use is None or base_url is None: if domain_to_use is None or base_url is None:

View File

@ -24,7 +24,6 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
media_search_manager = MediaManager() media_search_manager = MediaManager()
table_show_manager = TVShowManager() table_show_manager = TVShowManager()
max_timeout = config_manager.get_int("REQUESTS", "timeout") max_timeout = config_manager.get_int("REQUESTS", "timeout")
disable_searchDomain = config_manager.get_bool("DEFAULT", "disable_searchDomain")
def title_search(word_to_search: str) -> int: def title_search(word_to_search: str) -> int:
@ -40,10 +39,7 @@ def title_search(word_to_search: str) -> int:
media_search_manager.clear() media_search_manager.clear()
table_show_manager.clear() table_show_manager.clear()
# Find new domain if prev dont work # Check if domain is working
domain_to_use = site_constant.DOMAIN_NOW
if not disable_searchDomain:
domain_to_use, base_url = search_domain(site_constant.SITE_NAME, site_constant.FULL_URL) domain_to_use, base_url = search_domain(site_constant.SITE_NAME, site_constant.FULL_URL)
if domain_to_use is None or base_url is None: if domain_to_use is None or base_url is None:

View File

@ -26,7 +26,6 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
media_search_manager = MediaManager() media_search_manager = MediaManager()
table_show_manager = TVShowManager() table_show_manager = TVShowManager()
max_timeout = config_manager.get_int("REQUESTS", "timeout") max_timeout = config_manager.get_int("REQUESTS", "timeout")
disable_searchDomain = config_manager.get_bool("DEFAULT", "disable_searchDomain")
def title_search(title_search: str) -> int: def title_search(title_search: str) -> int:
@ -39,9 +38,6 @@ def title_search(title_search: str) -> int:
Returns: Returns:
int: The number of titles found. int: The number of titles found.
""" """
domain_to_use = site_constant
if not disable_searchDomain:
domain_to_use, base_url = search_domain(site_constant.SITE_NAME, site_constant.FULL_URL) domain_to_use, base_url = search_domain(site_constant.SITE_NAME, site_constant.FULL_URL)
if domain_to_use is None or base_url is None: if domain_to_use is None or base_url is None:

View File

@ -13,7 +13,7 @@ from StreamingCommunity.Util.table import TVShowManager
# Config # Config
MAP_EPISODE = config_manager.get('DEFAULT', 'map_episode_name') MAP_EPISODE = config_manager.get('OUT_FOLDER', 'map_episode_name')
def dynamic_format_number(n: int) -> str: def dynamic_format_number(n: int) -> str:

View File

@ -29,7 +29,7 @@ class SiteConstant:
@property @property
def ROOT_PATH(self): def ROOT_PATH(self):
return config_manager.get('DEFAULT', 'root_path') return config_manager.get('OUT_FOLDER', 'root_path')
@property @property
def DOMAIN_NOW(self): def DOMAIN_NOW(self):
@ -42,23 +42,23 @@ class SiteConstant:
@property @property
def SERIES_FOLDER(self): def SERIES_FOLDER(self):
base_path = self.ROOT_PATH base_path = self.ROOT_PATH
if config_manager.get_bool("DEFAULT", "add_siteName"): if config_manager.get_bool("OUT_FOLDER", "add_siteName"):
base_path = os.path.join(base_path, self.SITE_NAME) base_path = os.path.join(base_path, self.SITE_NAME)
return os.path.join(base_path, config_manager.get('DEFAULT', 'serie_folder_name')) return os.path.join(base_path, config_manager.get('OUT_FOLDER', 'serie_folder_name'))
@property @property
def MOVIE_FOLDER(self): def MOVIE_FOLDER(self):
base_path = self.ROOT_PATH base_path = self.ROOT_PATH
if config_manager.get_bool("DEFAULT", "add_siteName"): if config_manager.get_bool("OUT_FOLDER", "add_siteName"):
base_path = os.path.join(base_path, self.SITE_NAME) base_path = os.path.join(base_path, self.SITE_NAME)
return os.path.join(base_path, config_manager.get('DEFAULT', 'movie_folder_name')) return os.path.join(base_path, config_manager.get('OUT_FOLDER', 'movie_folder_name'))
@property @property
def ANIME_FOLDER(self): def ANIME_FOLDER(self):
base_path = self.ROOT_PATH base_path = self.ROOT_PATH
if config_manager.get_bool("DEFAULT", "add_siteName"): if config_manager.get_bool("OUT_FOLDER", "add_siteName"):
base_path = os.path.join(base_path, self.SITE_NAME) base_path = os.path.join(base_path, self.SITE_NAME)
return os.path.join(base_path, config_manager.get('DEFAULT', 'anime_folder_name')) return os.path.join(base_path, config_manager.get('OUT_FOLDER', 'anime_folder_name'))
@property @property
def COOKIE(self): def COOKIE(self):

View File

@ -99,7 +99,7 @@ class PathManager:
Creates a hash-based filename if no path is provided. Creates a hash-based filename if no path is provided.
""" """
if not path: if not path:
root = config_manager.get('DEFAULT', 'root_path') root = config_manager.get('OUT_FOLDER', 'root_path')
hash_name = compute_sha1_hash(self.m3u8_url) + ".mp4" hash_name = compute_sha1_hash(self.m3u8_url) + ".mp4"
return os.path.join(root, "undefined", hash_name) return os.path.join(root, "undefined", hash_name)

View File

@ -212,9 +212,6 @@ def main(script_id = 0):
parser.add_argument( parser.add_argument(
'--add_siteName', type=bool, help='Enable or disable adding the site name to the file name (e.g., true/false).' '--add_siteName', type=bool, help='Enable or disable adding the site name to the file name (e.g., true/false).'
) )
parser.add_argument(
'--disable_searchDomain', type=bool, help='Enable or disable searching in configured domains (e.g., true/false).'
)
parser.add_argument( parser.add_argument(
'--not_close', type=bool, help='If set to true, the script will not close the console after execution (e.g., true/false).' '--not_close', type=bool, help='If set to true, the script will not close the console after execution (e.g., true/false).'
) )
@ -260,8 +257,6 @@ def main(script_id = 0):
if args.add_siteName is not None: if args.add_siteName is not None:
config_updates['DEFAULT.add_siteName'] = args.add_siteName config_updates['DEFAULT.add_siteName'] = args.add_siteName
if args.disable_searchDomain is not None:
config_updates['DEFAULT.disable_searchDomain'] = args.disable_searchDomain
if args.not_close is not None: if args.not_close is not None:
config_updates['DEFAULT.not_close'] = args.not_close config_updates['DEFAULT.not_close'] = args.not_close
if args.default_video_worker is not None: if args.default_video_worker is not None:

View File

@ -4,23 +4,28 @@
"show_message": true, "show_message": true,
"clean_console": true, "clean_console": true,
"show_trending": true, "show_trending": true,
"use_api": true,
"not_close": false,
"telegram_bot": false
},
"OUT_FOLDER": {
"root_path": "Video", "root_path": "Video",
"movie_folder_name": "Movie", "movie_folder_name": "Movie",
"serie_folder_name": "Serie", "serie_folder_name": "Serie",
"anime_folder_name": "Anime", "anime_folder_name": "Anime",
"map_episode_name": "E%(episode)_%(episode_name)", "map_episode_name": "E%(episode)_%(episode_name)",
"use_api": true, "add_siteName": false
"add_siteName": false, },
"disable_searchDomain": false, "QBIT_CONFIG": {
"not_close": false, "host": "192.168.1.51",
"telegram_bot": false "port": "6666",
"user": "admin",
"pass": "adminadmin"
}, },
"REQUESTS": { "REQUESTS": {
"verify": false, "verify": false,
"timeout": 20, "timeout": 20,
"max_retry": 8, "max_retry": 8
"proxy_start_min": 0.1,
"proxy_start_max": 0.5
}, },
"M3U8_DOWNLOAD": { "M3U8_DOWNLOAD": {
"tqdm_delay": 0.01, "tqdm_delay": 0.01,
@ -58,11 +63,5 @@
"ips4_member_id": "", "ips4_member_id": "",
"ips4_login_key": "" "ips4_login_key": ""
} }
},
"QBIT_CONFIG": {
"host": "192.168.1.51",
"port": "6666",
"user": "admin",
"pass": "adminadmin"
} }
} }