APP下载 微博 微信

Hao4K影音


[音乐资源] 免费下载Qobuz音乐平台音乐机器人

[复制链接]

发表于 2024年02月28日 12:47 4185 11 来源:高级Hi-Fi> 音乐资源 |只看大图 回帖奖励 |倒序浏览 |

小uu 帖主

2024-2-28 12:47


转自微信公众号 侯plus
Qobuz音乐平台介绍
264b1528e097b4de9076cc75e362f429.png

Qobuz是一个受欢迎的音乐流媒体平台,提供超过1亿首歌曲的访问。

所有歌曲均以高保真的FLAC(无损音频编解码器)格式提供。

凭借其令人印象深刻的音频质量和广泛的目录,Qobuz已成为音响发烧友和音乐爱好者的首选平台。

Qobuz于2007年在法国创立。

Qubuz在无损音乐方面最高能提供24bit/192kHz规格的高解析度无损音乐。

但与TIDAL不同的是,TIDAL在高解析度音乐是采用MQA编码后进行传输的,同样规格下的传输码流要比Qobuz要小,而Qobuz不采用MQA编码(MQA为有损编码),传输码流相对更大。

月付费是13刀一个月,我们要搬运Qobuz的音乐需要至少一个收费账户。


2a3114d99c75bca06e5af027f477d04b.png
23e9be1216e085f21780e273bd36d306.png
搬运机器人框架添加proxy模块

github上有qobuz的下载机器人框架,我选择的是Sorrow446写的Qo-DL下载机器人框架。

不过这个代码年久失修,已经有5年没有更新,和最新的网页已经不能适配,需要自己修补和改造。

具体网页解析功能修补的过程不再赘述,每次网页改版均需要升级代码做适配。主要记录下主程序改造的过程。

首先qobuz在国内是无法登录的,需要飞机场。

机器人框架不支持飞机场需要做第一个改造,添加proxy模块。

在qopy.py中添加proxy,代码参考如下:

  1. class Client:
  2.     def __init__(self, email, <font color="#0086b3">pwd</font>, app_id, secrets):
  3.         logger.info(f<font color="#d14">"{YELLOW}Logging...,app_id是{app_id}"</font>)
  4.         self.secrets = secrets
  5.         self.id = str(app_id)
  6.         self.session = requests.Session()
  7.         self.session.proxies = {<font color="#d14">'https://127.0.0.1'</font>: <font color="#d14">'foo.bar:1081'</font>}
  8.         self.session.headers.update(
  9.             {
  10.                 <font color="#d14">"User-Agent"</font>: <font color="#d14">"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0"</font>,
  11.                 <font color="#d14">"X-App-Id"</font>: self.id,
  12.                 <font color="#d14">"Content-Type"</font>: <font color="#d14">"application/json;charset=UTF-8"</font>,
  13.                 <font color="#d14">'Connection'</font>: <font color="#d14">'close'</font>

  14.             }
  15.         )
  16.         self.base = <font color="#d14">"https://www.qobuz.com/api.json/0.2/"</font>
  17.         self.sec = None
  18.         self.auth(email, <font color="#0086b3">pwd</font>)
  19.         self.cfg_setup()
复制代码


搬运机器人框架改造专辑下载模块

在对qobuz平台的地址解析改造完成后,需要对专辑下载模块进行改造。

专辑下载模块存在的主要问题是limit固定是500,也就是只能一次最多下载500首歌。

通过改造可以绕过limit限制,进行无限制的下载。

  • 机器人框架download模块的改造

    download模块改造函数def download_release(self),改造前代码:

       
    1. def download_release(self):
    2.         count = 0
    3.         meta = self.client.get_album_meta(self.item_id)

    4.         <font color="#333"><b>if</b></font> not meta.get(<font color="#d14">"streamable"</font>):
    5.             raise NonStreamable(<font color="#d14">"This release is not streamable"</font>)

    6.         <font color="#333"><b>if</b></font> self.albums_only and (
    7.             meta.get(<font color="#d14">"release_type"</font>) != <font color="#d14">"album"</font>
    8.             or meta.get(<font color="#d14">"artist"</font>).get(<font color="#d14">"name"</font>) == <font color="#d14">"Various Artists"</font>
    9.         ):
    10.             logger.info(f<font color="#d14">'{OFF}Ignoring Single/EP/VA: {meta.get("title", "n/a")}'</font>)
    11.             <font color="#0086b3">return</font>

    12.         album_title = _get_title(meta)

    13.         format_info = self._get_format(meta)
    14.         file_format, quality_met, bit_depth, sampling_rate = format_info

    15.         <font color="#333"><b>if</b></font> not self.downgrade_quality and not quality_met:
    16.             logger.info(
    17.                 f<font color="#d14">"{OFF}Skipping {album_title} as it doesn't meet quality requirement"</font>
    18.             )
    19.             <font color="#0086b3">return</font>

    20.         logger.info(
    21.             f<font color="#d14">"\n{YELLOW}Downloading: {album_title}\nQuality: {file_format}"</font>
    22.             f<font color="#d14">" ({bit_depth}/{sampling_rate})\n"</font>
    23.         )
    24.         album_attr = self._get_album_attr(
    25.             meta, album_title, file_format, bit_depth, sampling_rate
    26.         )
    27.         folder_format, track_format = _clean_format_str(
    28.             self.folder_format, self.track_format, file_format
    29.         )
    30.         sanitized_title = sanitize_filepath(folder_format.format(**album_attr))
    31.         dirn = os.path.join(self.path, sanitized_title)
    32.         os.makedirs(dirn, exist_ok=True)

    33.         <font color="#333"><b>if</b></font> self.no_cover:
    34.             logger.info(f<font color="#d14">"{OFF}Skipping cover"</font>)
    35.         <font color="#333"><b>else</b></font>:
    36.             _get_extra(meta[<font color="#d14">"image"</font>][<font color="#d14">"large"</font>], dirn, og_quality=self.cover_og_quality)

    37.         <font color="#333"><b>if</b></font> <font color="#d14">"goodies"</font> <font color="#333"><b>in</b></font> meta:
    38.             try:
    39.                 _get_extra(meta[<font color="#d14">"goodies"</font>][0][<font color="#d14">"url"</font>], dirn, <font color="#d14">"booklet.pdf"</font>)
    40.             except:  <font color="#998"><i># noqa</i></font>
    41.                 pass
    42.         media_numbers = [track[<font color="#d14">"media_number"</font>] <font color="#333"><b>for</b></font> track <font color="#333"><b>in</b></font> meta[<font color="#d14">"tracks"</font>][<font color="#d14">"items"</font>]]
    43.         is_multiple = True <font color="#333"><b>if</b></font> len([*{*media_numbers}]) > 1 <font color="#333"><b>else</b></font> False
    44.         <font color="#333"><b>for</b></font> i <font color="#333"><b>in</b></font> meta[<font color="#d14">"tracks"</font>][<font color="#d14">"items"</font>]:
    45.             parse = self.client.get_track_url(i[<font color="#d14">"id"</font>], fmt_id=self.quality)
    46.             <font color="#333"><b>if</b></font> <font color="#d14">"sample"</font> not <font color="#333"><b>in</b></font> parse and parse[<font color="#d14">"sampling_rate"</font>]:
    47.                 is_mp3 = True <font color="#333"><b>if</b></font> int(self.quality) == 5 <font color="#333"><b>else</b></font> False
    48.                 self._download_and_tag(
    49.                     dirn,
    50.                     count,
    51.                     parse,
    52.                     i,
    53.                     meta,
    54.                     False,
    55.                     is_mp3,
    56.                     i[<font color="#d14">"media_number"</font>] <font color="#333"><b>if</b></font> is_multiple <font color="#333"><b>else</b></font> None,
    57.                 )
    58.             <font color="#333"><b>else</b></font>:
    59.                 logger.info(f<font color="#d14">"{OFF}Demo. Skipping"</font>)
    60.             count = count + 1
    61.         logger.info(f<font color="#d14">"{GREEN}Completed"</font>)
    复制代码

    改造后代码:

       
    1. def download_release(self):
    2.         count = 0
    3.         meta_lists = self.client.get_album_meta(self.item_id)
    4.         <font color="#333"><b>for</b></font> meta <font color="#333"><b>in</b></font> meta_lists:
    5.             <font color="#333"><b>if</b></font> not meta.get(<font color="#d14">"streamable"</font>):
    6.                 raise NonStreamable(<font color="#d14">"This release is not streamable"</font>)

    7.             <font color="#333"><b>if</b></font> self.albums_only and (
    8.                     meta.get(<font color="#d14">"release_type"</font>) != <font color="#d14">"album"</font>
    9.                     or meta.get(<font color="#d14">"artist"</font>).get(<font color="#d14">"name"</font>) == <font color="#d14">"Various Artists"</font>
    10.             ):
    11.                 logger.info(f<font color="#d14">'{OFF}Ignoring Single/EP/VA: {meta.get("title", "n/a")}'</font>)
    12.                 <font color="#0086b3">return</font>

    13.             album_title = _get_title(meta)

    14.             format_info = self._get_format(meta)
    15.             file_format, quality_met, bit_depth, sampling_rate = format_info

    16.             <font color="#333"><b>if</b></font> not self.downgrade_quality and not quality_met:
    17.                 logger.info(
    18.                     f<font color="#d14">"{OFF}Skipping {album_title} as it doesn't meet quality requirement"</font>
    19.                 )
    20.                 <font color="#0086b3">return</font>

    21.             logger.info(
    22.                 f<font color="#d14">"\n{YELLOW}Downloading: {album_title}\nQuality: {file_format}"</font>
    23.                 f<font color="#d14">" ({bit_depth}/{sampling_rate})\n"</font>
    24.             )
    25.             album_attr = self._get_album_attr(
    26.                 meta, album_title, file_format, bit_depth, sampling_rate
    27.             )
    28.             folder_format, track_format = _clean_format_str(
    29.                 self.folder_format, self.track_format, file_format
    30.             )
    31.             sanitized_title = sanitize_filepath(folder_format.format(**album_attr))
    32.             dirn = os.path.join(self.path, sanitized_title)
    33.             os.makedirs(dirn, exist_ok=True)

    34.             <font color="#333"><b>if</b></font> self.no_cover:
    35.                 logger.info(f<font color="#d14">"{OFF}Skipping cover"</font>)
    36.             <font color="#333"><b>else</b></font>:
    37.                 _get_extra(meta[<font color="#d14">"image"</font>][<font color="#d14">"large"</font>], dirn, og_quality=self.cover_og_quality)

    38.             <font color="#333"><b>if</b></font> <font color="#d14">"goodies"</font> <font color="#333"><b>in</b></font> meta:
    39.                 try:
    40.                     _get_extra(meta[<font color="#d14">"goodies"</font>][0][<font color="#d14">"url"</font>], dirn, <font color="#d14">"booklet.pdf"</font>)
    41.                 except:  <font color="#998"><i># noqa</i></font>
    42.                     pass
    43.             media_numbers = [track[<font color="#d14">"media_number"</font>] <font color="#333"><b>for</b></font> track <font color="#333"><b>in</b></font> meta[<font color="#d14">"tracks"</font>][<font color="#d14">"items"</font>]]
    44.             is_multiple = True <font color="#333"><b>if</b></font> len([*{*media_numbers}]) > 1 <font color="#333"><b>else</b></font> False
    45.             <font color="#333"><b>for</b></font> i <font color="#333"><b>in</b></font> meta[<font color="#d14">"tracks"</font>][<font color="#d14">"items"</font>]:
    46.                 parse = self.client.get_track_url(i[<font color="#d14">"id"</font>], fmt_id=self.quality)
    47.                 <font color="#333"><b>if</b></font> <font color="#d14">"sample"</font> not <font color="#333"><b>in</b></font> parse and parse[<font color="#d14">"sampling_rate"</font>]:
    48.                     is_mp3 = True <font color="#333"><b>if</b></font> int(self.quality) == 5 <font color="#333"><b>else</b></font> False
    49.                     self._download_and_tag(
    50.                         dirn,
    51.                         count,
    52.                         parse,
    53.                         i,
    54.                         meta,
    55.                         False,
    56.                         is_mp3,
    57.                         i[<font color="#d14">"media_number"</font>] <font color="#333"><b>if</b></font> is_multiple <font color="#333"><b>else</b></font> None,
    58.                     )
    59.                 <font color="#333"><b>else</b></font>:
    60.                     logger.info(f<font color="#d14">"{OFF}Demo. Skipping"</font>)
    61.                 count = count + 1
    62.             logger.info(f<font color="#d14">"{GREEN}Completed"</font>)
    复制代码

  • 机器人框架qopy模块的改造

    qopy模块主要改造def get_album_meta(self, id)函数,改造前代码:

       
    1. def get_album_meta(self, id):
    2.         <font color="#0086b3">return</font> self.api_call(<font color="#d14">"album/get"</font>, id=id)
    复制代码

    改造后代码:

      
    1. def get_album_meta(self, id):
    2.         <font color="#0086b3">limit</font> = 500
    3.         offset = 0
    4.         meta_lists = []
    5.         meta_url = self.api_call(<font color="#d14">"album/get"</font>, id=id, offset=offset)
    6.         total = meta_url[<font color="#d14">"tracks"</font>][<font color="#d14">"total"</font>]
    7.         logger.info(f<font color="#d14">"{YELLOW}{total} albums in the albums !"</font>)
    8.         <font color="#333"><b>while</b></font> total > 0:
    9.             meta = self.api_call(
    10.                 <font color="#d14">"album/get"</font>, id=id, offset=offset)
    11.             meta_lists.append(meta)
    12.             total -= <font color="#0086b3">limit</font>
    13.             offset += 1
    14.         <font color="#0086b3">return</font> meta_lists
    复制代码

    主要作用是添加了offset参数给网址做解析,每次解析是500条,超过500条offset参数加一,再解析第501到第1000条。

    qopy模块改造def api_call(self, epoint, **kwargs)函数,改造前代码:

    1. def api_call(self, epoint, **kwargs):
    2.         <font color="#333"><b>if</b></font> epoint == <font color="#d14">"user/login"</font>:
    3.             params = {
    4.                 <font color="#d14">"email"</font>: kwargs[<font color="#d14">"email"</font>],
    5.                 <font color="#d14">"password"</font>: kwargs[<font color="#d14">"pwd"</font>],
    6.                 <font color="#d14">"app_id"</font>: self.id,
    7.             }
    8.         <font color="#333"><b>elif</b></font> epoint == <font color="#d14">"track/get"</font>:
    9.             params = {<font color="#d14">"track_id"</font>: kwargs[<font color="#d14">"id"</font>]}
    10.         <font color="#333"><b>elif</b></font> epoint == <font color="#d14">"album/get"</font>:
    11.             params = {<font color="#d14">"album_id"</font>: kwargs[<font color="#d14">"id"</font>]}
    复制代码

    改造后代码:

       
    1. def api_call(self, epoint, **kwargs):
    2.         <font color="#333"><b>if</b></font> epoint == <font color="#d14">"user/login"</font>:
    3.             params = {
    4.                 <font color="#d14">"email"</font>: kwargs[<font color="#d14">"email"</font>],
    5.                 <font color="#d14">"password"</font>: kwargs[<font color="#d14">"pwd"</font>],
    6.                 <font color="#d14">"app_id"</font>: self.id,
    7.             }
    8.         <font color="#333"><b>elif</b></font> epoint == <font color="#d14">"track/get"</font>:
    9.             params = {<font color="#d14">"track_id"</font>: kwargs[<font color="#d14">"id"</font>]}
    10.         <font color="#333"><b>elif</b></font> epoint == <font color="#d14">"album/get"</font>:
    11.             params = {<font color="#d14">"album_id"</font>: kwargs[<font color="#d14">"id"</font>],
    12.                       <font color="#d14">"offset"</font>: kwargs[<font color="#d14">"offset"</font>],
    13.                       }
    复制代码

  • qobuz机器人下载进度条改造

    进度条由download模块的def tqdm_download(url, fname, desc, max_retries=10)函数进行控制,改造前代码:

    1. def tqdm_download(url, fname, desc):
    2.     r = requests.get(url, allow_redirects=True, stream=True)
    3.     total = int(r.headers.get(<font color="#d14">"content-length"</font>, 0))
    4.     download_size = 0
    5.     with open(fname, <font color="#d14">"wb"</font>) as file, tqdm(
    6.         total=total,
    7.         unit=<font color="#d14">"iB"</font>,
    8.         unit_scale=True,
    9.         unit_divisor=1024,
    10.         desc=desc,
    11.         bar_format=CYAN + <font color="#d14">"{n_fmt}/{total_fmt} /// {desc}"</font>,
    12.     ) as bar:
    13.         <font color="#333"><b>for</b></font> data <font color="#333"><b>in</b></font> r.iter_content(chunk_size=1024):
    14.             size = file.write(data)
    15.             bar.update(size)
    16.             download_size += size
    17.     <font color="#333"><b>if</b></font> total != download_size:
    18.         <font color="#998"><i># <a href="https://stackoverflow.com/questions/69919912/requests-iter-content-thinks-file-is-complete-but-its-not" target="_blank">https://stackoverflow.com/questi ... omplete-but-its-not</a></i></font>
    19.         raise ConnectionError(<font color="#d14">"File download was interrupted for "</font> + fname)
    复制代码

    改造后代码:

    1. def tqdm_download(url, fname, desc, max_retries=10):
    2.     pbar = None
    3.     miniters = 10  <font color="#998"><i># 设置 miniters 参数,以达到动态进度条效果</i></font>
    4.     <font color="#333"><b>for</b></font> retry_count <font color="#333"><b>in</b></font> range(max_retries):
    5.         try:
    6.             r = requests.get(url,
    7.                              allow_redirects=True,
    8.                              stream=False,
    9.                              timeout=30,
    10.                              headers={<font color="#d14">'Connection'</font>: <font color="#d14">'close'</font>}, )  <font color="#998"><i># 增加超时时间</i></font>
    11.             r.raise_for_status()
    12.             total = int(r.headers.get(<font color="#d14">"content-length"</font>, 0))
    13.             download_size = 0
    14.             with open(fname, <font color="#d14">"wb"</font>) as file:
    15.                 pbar = tqdm(
    16.                     total=total,
    17.                     unit=<font color="#d14">"iB"</font>,
    18.                     unit_scale=True,
    19.                     unit_divisor=1024,
    20.                     desc=desc,
    21.                     dynamic_ncols=True,  <font color="#998"><i># 使用 dynamic_ncols 参数显示实时速度</i></font>
    22.                     miniters=miniters,
    23.                     bar_format=CYAN + <font color="#d14">"{n_fmt}/{total_fmt} /// {desc} /// {rate_fmt}"</font>,
    24.                 )
    25.                 start_time = time.time()
    26.                 <font color="#333"><b>for</b></font> data <font color="#333"><b>in</b></font> r.iter_content(chunk_size=1024):
    27.                     size = file.write(data)
    28.                     pbar.update(size)
    29.                     download_size += size
    30.                     elapsed_time = time.time() - start_time
    31.                     current_speed = size / elapsed_time <font color="#333"><b>if</b></font> elapsed_time > 0 <font color="#333"><b>else</b></font> 0
    32.                     pbar.set_postfix(speed=f<font color="#d14">"{current_speed / 1024:.2f} KB/s"</font>)
    33.             <font color="#333"><b>if</b></font> total == download_size:
    34.                 <font color="#0086b3">break</font>  <font color="#998"><i># 下载成功,退出循环</i></font>
    35.             <font color="#333"><b>else</b></font>:
    36.                 <font color="#998"><i># <a href="https://stackoverflow.com/questions/69919912/requests-iter-content-thinks-file-is-complete-but-its-not" target="_blank">https://stackoverflow.com/questi ... omplete-but-its-not</a></i></font>
    37.                 raise ConnectionError(<font color="#d14">"File download was interrupted for "</font> + fname)
    38.         except (requests.exceptions.RequestException, ConnectionError, urllib3.exceptions.ProtocolError) as e:
    39.             logger.error(f<font color="#d14">"{RED}Error during download: {e}"</font>, exc_info=True)
    40.             <font color="#333"><b>if</b></font> retry_count < max_retries - 1:
    41.                 <font color="#998"><i># 间隔一段时间后进行下一次重试</i></font>
    42.                 time.sleep(5)
    43.                 <font color="#0086b3">continue</font>
    44.             <font color="#333"><b>else</b></font>:
    45.                 logger.error(f<font color="#d14">"{RED}Max retries reached. Unable to download: {fname}"</font>)
    46.                 <font color="#0086b3">break</font>  <font color="#998"><i># 如果达到最大重试次数仍然失败,退出循环</i></font>
    47.         finally:
    48.             <font color="#333"><b>if</b></font> pbar is not None:
    49.                 pbar.close()
    复制代码

    经过改造后就能正常搬运qobuz音乐平台几乎所有的音乐到本地存储了。



7193a2b80905ebba36a12327f72e7de1.png

cdec2b7d2cd6eab26627ccf2d5a21bb9.png

7e440a520ca37f9835a6ecb7b86fb02c.png



回复

使用道具 举报

全部回复11

强哥xu 2

2024-2-28 13:51

〈兔子〉网站上也开发了可以从Qobus搬运文件,转入〈兔云〉的功能。
回复 支持 反对

使用道具 举报

hao4k 3

2024-2-28 14:31

强哥xu 发表于 2024-2-28 13:51
〈兔子〉网站上也开发了可以从Qobus搬运文件,转入〈兔云〉的功能。

是嘛,强哥说的兔子网站是指的那个呀,好用不,方便还请告知一下。我去研究研究
回复 支持 反对

使用道具 举报

强哥xu 4

2024-2-28 14:34

本帖最后由 强哥xu 于 2024-2-28 15:09 编辑
强哥xu 发表于 2024-2-28 13:51
〈兔子〉网站上也开发了可以从Qobus搬运文件,转入〈兔云〉的功能。


有个Apple Music还是真的方便,在〈兔子〉网上看到个音频文件,无需下载,直接上Apple Music捜索,就可直接播放。再来。(仅限于pcm.dsd不能!)
更多图片 小图 大图
组图打开中,请稍候......
回复 支持 反对

使用道具 举报

强哥xu 5

2024-2-28 14:36

本帖最后由 强哥xu 于 2024-2-28 15:07 编辑
hao4k 发表于 2024-2-28 14:31
是嘛,强哥说的兔子网站是指的那个呀,好用不,方便还请告知一下。我去研究研究


(音)。我没有Qobus的账号,没实操过。等你探索成功。
IMG_20240228_150237.jpg
回复 支持 反对

使用道具 举报

hao4k 6

2024-2-28 15:07

强哥xu 发表于 2024-2-28 14:36
(音)。我没有Qobus的账号,没实操过。等你探索成功。

好像找到强哥说的这个兔子网了,但是打不开,似乎在维护升级中...
回复 支持 反对

使用道具 举报

强哥xu 7

2024-2-28 15:17

hao4k 发表于 2024-2-28 15:07
好像找到强哥说的这个兔子网了,但是打不开,似乎在维护升级中...

应该不是。“人怕出名猪怕壮”。哈哈哈。是为了怕“和谐”。之前,我通过〈度盘〉下载很方便,速度又快。现在它搬移至自己的网盘,免费下载就较麻烦且慢,除非买会员。
回复 支持 反对

使用道具 举报

hao4k 8

2024-2-28 16:14

强哥xu 发表于 2024-2-28 15:17
应该不是。“人怕出名猪怕壮”。哈哈哈。是为了怕“和谐”。之前,我通过〈度盘〉下载很方便,速度又快。 ...

刚才居然找到了山寨版的音兔网了,哈哈。
已经找到正确的音兔网,感谢强哥的截图,我研究一下。
回复 支持 反对

使用道具 举报

强哥xu 9

2024-2-28 18:14

hao4k 发表于 2024-2-28 16:14
刚才居然找到了山寨版的音兔网了,哈哈。
已经找到正确的音兔网,感谢强哥的截图,我研究一下。

看这帖子,Qobuz这么麻烦,又是“机场”,又是海外账户,收费相对又高,(13美刀/月)你还不如开Apple Music账号。(11RMB/月)
回复 支持 反对

使用道具 举报

hao4k 10

2024-2-28 19:53

强哥xu 发表于 2024-2-28 18:14
看这帖子,Qobuz这么麻烦,又是“机场”,又是海外账户,收费相对又高,(13美刀/月)你还不如开Apple Mu ...

如果我们研究成功的话,就可以供咱们论坛发烧友一起使用了,13美刀一个月就不算什么了
回复 支持 反对

使用道具 举报

强哥xu 11

2024-2-28 21:03

hao4k 发表于 2024-2-28 19:53
如果我们研究成功的话,就可以供咱们论坛发烧友一起使用了,13美刀一个月就不算什么了

好人。提前感谢。我还当是你自己用呢。
回复 支持 反对

使用道具 举报

心的归程 12

2024-3-1 06:53

没专业一点的,很不容易明白,点赞了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

返回列表 本版积分规则



绑定微信 + 关注公众号,第一时间获得消息通知!
:
中级发烧友
:
介绍未填写

主题

帖子

积分5917

Hao4K影音app客户端下载