找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
查看: 18035|回复: 0

[技术讨论] PowerShell看RAR分割檔裡的mp4(缺檔)

[复制链接]
发表于 2016-11-4 21:35:37 | 显示全部楼层 |阅读模式
以下方法使用條件:
        壓縮方式:僅儲存
        至少要有:第一檔
                最後一檔(mp4的重要資訊在檔尾。如果最後一檔太小,可能需要倒數第二檔)

方法1:個別解出來、再合併

        7-Zip可以個別解出每個分割檔的內容
        計算「缺檔大小」 = mp4大小 - 已解出的總合
        產生符合「缺檔大小」的檔案,再依順序合併檔案

        也許可以用到 fsutil file
                     fsutil sparse
                        (沒測試)
方法2:自己補檔

        缺少的是中間檔(第一檔、最後一檔以外的檔案)
        並且有其他中間檔存在

        例如:目前有 part1  part2  part4  part5
                缺少 part3

        把其中一個中間檔複製並改名成「缺檔的檔名」
        例如:
                把part2 複製並改名成part3

        然後,就可以用MPC-HC、VLC player、Potplayer來看


方法3:掛載(mount)RAR分割檔

需要 PowerShell 5.0

分割檔限制:
        壓縮方式:僅儲存
        壓縮檔格式:RAR (不是新的RAR5)
        壓縮時所設定的分割檔大小:每一個分割檔都一樣大 (除了最後一檔)
        下載後的分割檔大小:可以下載到一半、沒有下載完成
        不能處理檔名加密的RAR檔(一般加密可以處理)

        至少要有:第一檔
                最後一檔(mp4的重要資訊在檔尾。如果最後一檔太小,可能需要倒數第二檔)



下載:
        到http://pismotec.com/download/
        下載並安裝 Pismo File Mount Audit Package

        下載Pismo File Mount Developer Kit
        取得pfmclr_183.dll、pfmshim16_183.dll
        分別在這兩個dll 按右鍵 → 內容 → 解除封鎖

執行方式:
        pfmclr_183.dll
        pfmshim16_183.dll
        RAR分割檔
        ps1

        把這些東西放在一起,執行 ps1 (不要用「管理員權限」開啟)

執行之後:
        要自己去找新掛載的磁碟機(它不會自己彈出來)
        如果沒加密,磁碟機裡的是mp4,可以直接打開
        如果有加密,磁碟機裡的是rar,要用WinRAR開啟 (會出現錯誤訊息)
                                        解壓縮 (保留毀損的檔案)


卸載:
        關掉PS視窗就卸載了。
        卸載方面有問題。
        卸載之後,打開Powershell視窗,會出現
                嘗試在 'FileSystem' 提供者上執行 InitializeDefaultDrives 作業失敗。

        如果要完全卸載,請重新開機
  1. #Requires -version 5.0
  2. if ($host.Version.Major -lt 5){write-host '需要 PowerShell 5.0';pause;exit}


  3. $dllfiles = @(gi pfmclr_183.dll , pfmshim16_183.dll )
  4. if ( $dllfiles.length -lt 2 ){
  5.         write-host '需要dll';pause;exit
  6. }else{
  7.         Add-Type  -literal  $dllfiles[0]
  8. }



  9. #分析RAR================================================================================
  10. $rarGroup = dir *.part*.rar | sort |?{$_.name -match '(.*)\.part(\d+)\.rar$' } |
  11.                         group -prop {$matches[1] + '/' + $matches[2].length}

  12. for ($i = 0 ; $i -lt $rarGroup.length; $i++){
  13.         if ($rarGroup[$i].group[0] -match 't0*1\.rar$'){
  14.                 $rar = $rarGroup[$i].group ; $nFiles = $rarGroup[$i].Count ; break}
  15. }
  16. if ($i -eq $rarGroup.lenth) {write-host '找不到第一檔';pause;exit}
  17. if ($nFiles -eq 1) {write-host '只有一檔,不用處理了';pause;exit}


  18. $fs = $rar[0].OpenRead()
  19. $buffer = new-object byte[](2kb)


  20. $n = $fs.read($buffer , 0 , 20)
  21. if ( $n -ne 20 ) {$fs.close();write-host '第一檔太小了';pause;exit}
  22. if ($buffer[10] -band 0x80){
  23.         $fs.close();write-host '不能處理檔名加密的RAR檔';pause;exit
  24. }

  25. $findOK = $false
  26. while ($fs.Position -lt $fs.length ){
  27.         $n = $fs.read($buffer , 20 , 7)
  28.         if ( $n -ne 7 ) {$fs.close();write-host '第一檔太小了';pause;stop-process -Id $PID}

  29.         $n = [BitConverter]::ToUInt16($buffer , 25) -7
  30.         if ( ($fs.Position + $n ) -gt $fs.length ){
  31.                 $fs.close();write-host '第一檔太小了';pause;stop-process -Id $PID
  32.         }
  33.         [void]$fs.read($buffer , 27 , $n)

  34.         #如果是檔案區塊
  35.         if ( $buffer[22] -eq 0x74 ) {
  36.                 #如果是mp4 -->  file continued in next volume
  37.                 if ( $buffer[23] -band 2 ) {
  38.                         #有沒有加密
  39.                         if ( $buffer[23] -band 4 ) { $encryption = $true} else { $encryption = $false}
  40.                         if ( $buffer[45] -ne 0x30) {
  41.                                 $fs.close();write-host '壓縮方式不是僅儲存';pause
  42.                                 stop-process -Id $PID
  43.                         }
  44.                         $HeaderSize = $n + 7
  45.                         $FirstSize = [BitConverter]::ToUInt32($buffer, 27 )
  46.                         $Mp4Size = [BitConverter]::ToUInt32($buffer, 31 )

  47.                         #如果檔案很大
  48.                         if  ($buffer[24] -band 1 ){
  49.                                 $HighSize = [BitConverter]::ToUInt32($buffer, 52 )
  50.                                 $FirstSize = ([long]$HighSize -shl 32 ) + $FirstSize

  51.                                 $HighSize = [BitConverter]::ToUInt32($buffer, 56 )
  52.                                 $Mp4Size = ([long]$HighSize -shl 32 ) + $Mp4Size
  53.                         }

  54.                         #取得檔名
  55.                         $nameSize = [BitConverter]::ToUInt16($buffer , 46 )
  56.                         if  ($buffer[24] -band 1 ){$namePos = 60 }else { $namePos = 52 }
  57.                         $mp4Name=[System.Text.Encoding]::Default.GetString($buffer,$namePos,$nameSize)
  58.                         $mp4Name = $mp4Name -replace '\x00.*',''  -replace '\?','_'
  59.                         $FirstOffset = $fs.Position
  60.                         $findOK = $true
  61.                         break

  62.                 }else{        #第一檔裡面的其他檔案
  63.                         $n = [BitConverter]::ToUInt32($buffer, 27)
  64.                         if  ($buffer[24] -band 1 ) {
  65.                                 $HighSize = [BitConverter]::ToUInt32($buffer, 52 )
  66.                                 $n += ([long]$HighSize -shl 32 )
  67.                         }
  68.                         if ( ($fs.Position + $n ) -gt $fs.length ){
  69.                                 $fs.close();write-host '第一檔太小了';pause;stop-process -Id $PID
  70.                         }
  71.                         $fs.Position += $n
  72.                 }
  73.         }else{#非檔案區塊
  74.                 if ($buffer[24] -band 0x80){
  75.                         $n = [BitConverter]::ToUInt32($buffer, 27)
  76.                                 if ( ($fs.Position + $n ) -gt $fs.length ){
  77.                                         $fs.close();write-host '第一檔太小了';pause;stop-process -Id $PID
  78.                                 }
  79.                         $fs.Position += $n
  80.                 }
  81.         }
  82. }
  83. $fs.close()
  84. if ( !$findOK) {write-host '沒找到mp4';pause;exit}
  85. #計算RAR資訊================================================================================
  86. $MidOffset = $LastOffset = $HeaderSize + 20
  87. $MidSize = $FirstSize + ( $FirstOffset - $MidOffset )
  88. $FullPack = $Mp4Size
  89. if ($encryption){
  90.         if ( $Mp4Size % 16 ) {        $FullPack += 16 - ($Mp4Size % 16) }
  91. }

  92. $LastSize = ($FullPack - $FirstSize) % $MidSize
  93. $nLastPart = ($FullPack - $FirstSize - $LastSize) / $MidSize +2

  94. $Mp4offset = $nEmpty = 0
  95. $mp4Info = & {
  96.         if ($encryption){
  97.                 $buffer[10] = $buffer[10] -band 238
  98.                 $buffer[11] = $buffer[11] -band 254
  99.                 $buffer[23] = $buffer[23] -band 253

  100.                 $fpbyte = [BitConverter]::GetBytes([uint64]$FullPack)
  101.                 [array]::copy($fpbyte,0,$buffer,27,4)
  102.                 if  ($buffer[24] -band 1 ){
  103.                         [array]::copy($fpbyte,4,$buffer,52,4)
  104.                 }                       

  105.                 @{fs = new-object IO.MemoryStream($buffer,0, (20 + $HeaderSize))
  106.                         Mp4offset = $Mp4offset        ;offset = 0 ; length = 20 + $HeaderSize
  107.                 }
  108.                 $Mp4offset += 20 + $HeaderSize
  109.         }
  110.         if (  ($FirstOffset + $FirstSize) -gt $rar[0].length  ) {
  111.                 $nEmpty = $FirstOffset + $FirstSize - $rar[0].length
  112.         }
  113.         @{fs = $rar[0].OpenRead() ; Mp4offset = $Mp4offset
  114.                 offset = $FirstOffset ; length = $FirstSize - $nEmpty
  115.         }

  116.         $Mp4offset += $FirstSize - $nEmpty
  117.         $nextN = 2

  118.         #$rar[index]
  119.         1.. ($nFiles - 1) | %{
  120.                 [int]$nPart = $rar[$_].basename -replace '.*part',''
  121.                 if ( $nPart -gt $nLastPart ) {
  122.                         @{fs = $null ; Mp4offset = $Mp4offset ; length = $FullPack - $Mp4offset}
  123.                         $nPart = $nLastPart ; return
  124.                 }

  125.                 if ( $nPart -gt $nextN  -or  $nEmpty -gt 0 ){
  126.                         @{fs = $null ; Mp4offset = $Mp4offset
  127.                                 length = $MidSize * ( $nPart - $nextN ) +  $nEmpty
  128.                         }
  129.                         $Mp4offset += $MidSize * ( $nPart - $nextN ) +  $nEmpty
  130.                         $nEmpty = 0
  131.                 }

  132.                 #如果是最後一檔
  133.                 if ( $nPart -eq $nLastPart ){
  134.                         if (  ($LastOffset + $LastSize) -gt $rar[$_].length  ) {
  135.                                 $nEmpty = $LastOffset + $LastSize - $rar[$_].length
  136.                         }
  137.                         @{fs = $rar[$_].OpenRead() ; Mp4offset = $Mp4offset
  138.                                 offset = $LastOffset ; length = $LastSize - $nEmpty
  139.                         }

  140.                         if ( $nEmpty -gt 0 ){
  141.                                 $Mp4offset += $LastSize - $nEmpty
  142.                                 @{fs = $null ; Mp4offset = $Mp4offset ; length = $nEmpty}
  143.                         }
  144.                         return

  145.                 }else{#中間檔
  146.                         if (  ($MidOffset + $MidSize) -gt $rar[$_].length  ) {
  147.                                 $nEmpty = $MidOffset + $MidSize - $rar[$_].length
  148.                         }
  149.                         @{fs = $rar[$_].OpenRead() ; Mp4offset = $Mp4offset
  150.                                 offset = $MidOffset ; length = $MidSize - $nEmpty
  151.                         }
  152.                         $Mp4offset += $MidSize - $nEmpty
  153.                         $nextN = $nPart + 1               
  154.                 }
  155.         }

  156.         if ( $nPart -lt $nLastPart ){
  157.                 @{fs = $null ; Mp4offset = $Mp4offset ; length = $FullPack - $Mp4offset}
  158.         }
  159. }
  160. #====================================================================================
  161. $RarVolumeType=@'
  162. #Learn from   Pismo File Mount Development Kit   samples\hellofs_cs\hellofs.cs
  163. class RarVolume: Pfm+FormatterDispatch{
  164.         $openRoot
  165.         $openFile1
  166.         $File1_name
  167.         $File1_info
  168. RarVolume(){
  169.         $this.openRoot = new-object Pfm+OpenAttribs -prop @{
  170.                                 openSequence = 1 ; accessLevel = [Pfm]::accessLevelReadData;
  171.                                 attribs = new-object Pfm+Attribs -prop @{fileType = [Pfm]::fileTypeFolder ; fileId = 2 }}

  172.         $this.openFile1 = new-object Pfm+OpenAttribs -prop @{
  173.                                 openSequence = 1 ; accessLevel = [Pfm]::accessLevelReadData;
  174.                                 attribs = new-object Pfm+Attribs -prop @{fileType = [Pfm]::fileTypeFile ; fileId = 3 }}
  175. }

  176. [void] Dispose(){}

  177. [void] Open( [Pfm+MarshallerOpenOp]$op){
  178.         $perr = 0
  179.         $existed = $false
  180.         $parentFileId = 0
  181.         $endName = $null
  182.         $openAttribs =  new-object Pfm+OpenAttribs
  183.         if ($op.NameParts().Length -eq 0){
  184.                 if ($this.openRoot.openId -eq 0) {$this.openRoot.openId = $op.NewExistingOpenId() }
  185.                 $existed = $true
  186.                 $openAttribs = $this.openRoot

  187.         }elseif($op.NameParts().Length -eq 1){
  188.                 if($op.NameParts()[0].ToLowerInvariant() -ne $this.File1_name.ToLowerInvariant()){
  189.                         $perr = [Pfm]::errorNotFound
  190.                 }else{
  191.                         if ($this.openFile1.openId -eq 0) {$this.openFile1.openId = $op.NewExistingOpenId() }
  192.                         $existed = $true
  193.                         $endName = $this.File1_name
  194.                         $openAttribs = $this.openFile1
  195.                 }

  196.         }else{  $perr = [Pfm]::errorParentNotFound }

  197.         if($perr -eq [Pfm]::errorNotFound -and $op.CreateFileType() -ne 0)
  198.         {        $perr = [Pfm]::errorAccessDenied          }

  199.         $op.Complete( $perr, $existed, $openAttribs, $parentFileId, $endName, 0, $null, 0, $null)
  200. }

  201. [void] Replace( [Pfm+MarshallerReplaceOp]$op){
  202.         $op.Complete( [Pfm]::errorAccessDenied, $null, $null)
  203. }

  204. [void] Move( [Pfm+MarshallerMoveOp] $op){
  205.         $op.Complete( [Pfm]::errorAccessDenied, $false, $null, 0, $null, 0, $null, 0, $null)
  206. }

  207. [void] MoveReplace( [Pfm+MarshallerMoveReplaceOp] $op){
  208.         $op.Complete( [Pfm]::errorAccessDenied)
  209. }

  210. [void] Delete( [Pfm+MarshallerDeleteOp] $op){
  211.         $op.Complete( [Pfm]::errorAccessDenied)
  212. }

  213. [void] Close( [Pfm+MarshallerCloseOp] $op){
  214.         $op.Complete( [Pfm]::errorSuccess)
  215. }

  216. [void] FlushFile( [Pfm+MarshallerFlushFileOp] $op){
  217.         $perr = 0
  218.         $openAttribs = new-object Pfm+OpenAttribs

  219.         if ( $op.FileFlags() -ne [Pfm]::fileFlagsInvalid -or
  220.                  $op.Color() -ne [Pfm]::colorInvalid -or
  221.                  $op.CreateTime() -ne [Pfm]::timeInvalid -or
  222.                  $op.WriteTime() -ne [Pfm]::timeInvalid){

  223.                 $perr = [Pfm]::errorAccessDenied

  224.         }elseif ($op.OpenId() -eq $this.openRoot.openId){

  225.                 $openAttribs = $this.openRoot

  226.         }elseif ($op.OpenId() -eq $this.openFile1.openId){

  227.                 $openAttribs = $this.openFile1
  228.         }else{
  229.                 $perr = [Pfm]::errorNotFound
  230.         }

  231.         $op.Complete( $perr, $openAttribs, $null)
  232. }

  233. [void] List( [Pfm+MarshallerListOp] $op){
  234.         $perr = 0
  235.         if ($op.OpenId() -ne $this.openRoot.openId){
  236.                 $perr = [Pfm]::errorAccessDenied
  237.         }else{
  238.                 $op.Add( $this.openFile1.attribs, $this.File1_name)
  239.         }

  240.         $op.Complete( $perr, $true)
  241. }

  242. [void] ListEnd( [Pfm+MarshallerListEndOp] $op){
  243.         $op.Complete( [Pfm]::errorSuccess)
  244. }

  245. [void] Read( [Pfm+MarshallerReadOp] $op){
  246.         $data = $op.Data()
  247.         $perr = 0
  248.         $actualSize = 0

  249.         if ($op.OpenId() -ne $this.openFile1.openId){
  250.                 $perr = [Pfm]::errorAccessDenied
  251.         }else{
  252.                 $actualSize = $op.RequestedSize()
  253.                 if ($op.FileOffset() -ge $this.openFile1.attribs.fileSize){
  254.                         $actualSize = 0
  255.                 }elseif ( (  $op.FileOffset() + $op.RequestedSize()) -gt $this.openFile1.attribs.fileSize){
  256.                         $actualSize = $this.openFile1.attribs.fileSize - $op.FileOffset()
  257.                 }

  258.                 if ($actualSize -ne 0){
  259.                         for ( $i = 1 ; $i -lt $this.File1_info.length ; $i++ ){
  260.                                 if ($op.FileOffset()  -lt $this.File1_info[$i].Mp4offset ){break}
  261.                         }                                       
  262.                         $i--

  263.                         if ($this.File1_info[$i].fs -ne $null ){
  264.                                 $this.File1_info[$i].fs.Position =
  265.                                         $op.FileOffset() - $this.File1_info[$i].Mp4offset + $this.File1_info[$i].offset
  266.                         }

  267.                         $aaa = $this.File1_info[$i].length - ( $op.FileOffset() - $this.File1_info[$i].Mp4offset)

  268.                         $offset = 0
  269.                         $actualSize1 = $actualSize
  270.                         while ($actualSize1 -gt 0){
  271.                                 if ($actualSize1 -gt $aaa ){
  272.                                         if ($this.File1_info[$i].fs -ne $null ){
  273.                                                 $this.File1_info[$i].fs.read($data , $offset , $aaa)
  274.                                         }else{
  275.                                                 [array]::Clear( $data , $offset , $aaa)
  276.                                         }
  277.                                         $actualSize1 -= $aaa
  278.                                         $offset += $aaa

  279.                                         $i++
  280.                                         if ($this.File1_info[$i].fs -ne $null ){
  281.                                                 $this.File1_info[$i].fs.Position = $this.File1_info[$i].offset
  282.                                         }
  283.                                         $aaa = $this.File1_info[$i].length
  284.                                 }else{
  285.                                         if ($this.File1_info[$i].fs -ne $null ){
  286.                                                 $this.File1_info[$i].fs.read($data , $offset , $actualSize1)
  287.                                         }else{
  288.                                                 [array]::Clear( $data , $offset , $actualSize1)
  289.                                         }
  290.                                         $actualSize1 = 0
  291.                                 }
  292.                         }

  293.                 }
  294.         }

  295.         $op.Complete( $perr, $actualSize)
  296. }

  297. [void] Write( [Pfm+MarshallerWriteOp] $op){
  298.         $op.Complete( [Pfm]::errorAccessDenied, 0)
  299. }

  300. [void] SetSize( [Pfm+MarshallerSetSizeOp] $op){
  301.         $op.Complete( [Pfm]::errorAccessDenied)
  302. }

  303. [void] Capacity( [Pfm+MarshallerCapacityOp] $op){
  304.         $op.Complete( [Pfm]::errorSuccess, 10TB, 9TB)
  305. }

  306. [void] FlushMedia( [Pfm+MarshallerFlushMediaOp] $op){
  307.         $op.Complete( [Pfm]::errorSuccess, -1)
  308. }

  309. [void] Control( [Pfm+MarshallerControlOp] $op){
  310.         $op.Complete( [Pfm]::errorInvalid, 0)
  311. }

  312. [void] MediaInfo( [Pfm+MarshallerMediaInfoOp] $op){
  313.         $mediaInfo = new-object Pfm+MediaInfo
  314.         $op.Complete( [Pfm]::errorSuccess, $mediaInfo, "RarMp4")
  315. }

  316. [void] Access( [Pfm+MarshallerAccessOp] $op){
  317.         $perr = 0
  318.         $openAttribs =  new-object Pfm+OpenAttribs

  319.         if ($op.OpenId() -eq $this.openRoot.openId){
  320.                 $openAttribs = $this.openRoot

  321.         }elseif($op.OpenId() -eq $this.openFile1.openId){
  322.                 $openAttribs = $this.openFile1

  323.         }else{
  324.                 $perr = [Pfm]::errorNotFound
  325.         }

  326.         $op.Complete( $perr, $openAttribs, $null)
  327. }

  328. [void] ReadXattr( [Pfm+MarshallerReadXattrOp] $op){
  329.         $op.Complete( [Pfm]::errorNotFound, 0, 0)
  330. }

  331. [void] WriteXattr( [Pfm+MarshallerWriteXattrOp] $op){
  332.         $op.Complete( [Pfm]::errorAccessDenied, 0)
  333. }


  334. }

  335. '@

  336. Invoke-Expression $RarVolumeType
  337. #開始掛載==================================================================================
  338. $mcp = new-object Pfm+MountCreateParams -prop @{
  339.         mountFlags = 1
  340.         driveLetter = "Z"
  341.         mountSourceName = "感謝大大無私分享"  }

  342. $msp = new-object Pfm+MarshallerServeParams  -prop @{
  343.         volumeFlags = 1
  344.         dispatch = new-object RarVolume
  345.         formatterName = "RarMp4Fs"  }


  346. $msp.dispatch.File1_name = split-path  $mp4Name  -leaf
  347. $msp.dispatch.openFile1.attribs.fileSize = $Mp4Size
  348. $msp.dispatch.File1_info = $mp4Info

  349. if ($encryption){
  350.         $msp.dispatch.File1_name = $msp.dispatch.File1_name +".rar"
  351.         $msp.dispatch.openFile1.attribs.fileSize = $FullPack + 20 + $HeaderSize

  352. }

  353. $n1 = $n2 = -1
  354. $err = [Pfm]::SystemCreatePipe( [ref] $n1, [ref]$n2 )
  355. $msp.toFormatterRead = $n1
  356. $mcp.toFormatterWrite = $n2
  357.       

  358. $n1 = $n2 = -1
  359. $err = [Pfm]::SystemCreatePipe( [ref] $n1, [ref]$n2 )
  360. $mcp.fromFormatterRead = $n1
  361. $msp.fromFormatterWrite = $n2        



  362. $pfmApi = $null
  363. $err = [Pfm]::ApiFactory( [ref] $pfmApi)
  364. if($err -ne 0){  Write-Host "ERROR: $err Unable to open PFM API.`n" ; pause ; exit }

  365. $mount = $null
  366. $err = $pfmApi.MountCreate( $mcp, [ref] $mount)
  367. if ($err -ne 0){ Write-Host "ERROR: $err Unable to create mount.`n"  }


  368. [Pfm]::SystemCloseFd( $mcp.toFormatterWrite)
  369. [Pfm]::SystemCloseFd( $mcp.fromFormatterRead)


  370. Write-Host "Press CTRL+C to exit.`n"
  371. $marshaller = $null
  372. $err = [Pfm]::MarshallerFactory( [ref]$marshaller )
  373. if($err -ne 0){  Write-Host "ERROR: $err Unable to create marshaller.`n" ; pause ; exit }
  374. $marshaller.ServeDispatch( $msp)


  375. [Pfm]::SystemCloseFd( $msp.toFormatterRead)
  376. [Pfm]::SystemCloseFd( $msp.fromFormatterWrite)


  377. $pfmApi.Dispose()
  378. $mount.Dispose()
  379. $marshaller.Dispose()
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-3-16 20:36 , Processed in 0.020735 second(s), 7 queries , File On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表