Mayaでreferenceをremoveしたい

パスのリンク切れとか、このアセットは使用しない等々の理由でunload状態のreferenceが溜まると、
一気にremoveしたくなります。


とりあえず設計
--
逆から考えて

- referenceをremoveする

為に

- referenceノードを指定する？

為に

- unload状態のreferenceノードを取得する?

かなぁー

個別に詰める
--

- **referenceをremoveする**

まずはこれの方法を調べます。

https://help.autodesk.com/cloudhelp/2022/JPN/Maya-Tech-Docs/CommandsPython/file.html

file コマンドの removeReference オプションを使用しようかなと。
書き方的には リファレンスしているファイルパスを引数に渡してますね。

```python
cmds.file(filePath, removeReference=True)
```
なので、リファレンスノードではなくリファレンス元のファイルパスが必要になってきました。
リファレンスしてるファイルパスの取得ですが、fileコマンドを使用するとすべて取得できます。

```python
allFilePath = cmds.file(q =True ,reference =True)
```

この中からアンロード状態のリファレンスだけを取得したいのですが、
リファレンスのロード状況を確認するにはreferenceQueryで出来そうです。

```python
loadState = cmds.referenceQuery(referenceNode,isLoaded=True)
```

ただしリファレンスノード名が引数となるのでリファレンスノードとファイルパスを紐づけた何かが欲しくなります。

fileコマンドで、ファイルパスを引数にして referenceNodeを問い合わせするとノード名が取得できます。

```python
referenceNode = cmds.file(filePath,q =True ,referenceNode = True)
```

これらをまとめると

- シーンでリファレンスしてるファイルパスをすべて取得
- ファイルパスから個別にリファレンスノードを取得し、ロード状態を確認
- アンロード状態のリファレンスをremove

という感じですね。
実際にスクリプト化してみるとこのようになりました。

```python
import maya.cmds as cmds
allFilePath = cmds.file(q =True ,reference =True)

for filePath in allFilePath:
    referenceNode = cmds.file(filePath,q =True ,referenceNode = True)
    loadState = cmds.referenceQuery(referenceNode,isLoaded=True)

    if loadState == False:
        cmds.file(filePath, removeReference=True)
        
```

テスト
--

この状態で実行すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/b8bde641-6d91-0b2f-6d4d-f15aac5feb21.png)

アンロード状態のリファレンスだけ削除されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/106de03e-7d23-4727-da00-ef4176413a97.png)


改修
--


たとえば、リファレンス元のファイルパスが存在しないものだけremoveしたい
場合には

```python

import maya.cmds as cmds
import os
allFilePath = cmds.file(q =True ,reference =True)

for filePath in allFilePath:
    referenceNode = cmds.file(filePath,q =True ,referenceNode = True)
    loadState = cmds.referenceQuery(referenceNode,isLoaded=True)

    if os.path.exists(filePath):
        continue
        
    if loadState == False:
        cmds.file(filePath, removeReference=True)

```

こんな感じでしょうか？

ひとまずさっきの状態で試してみると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/f00d9375-e159-c874-2fea-e2b7eb547643.png)

そのまま居残りました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/64d52da8-51df-0fd0-022f-b31b30f90cfe.png)

リファレンス元のファイル名を変更して実行してみると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/31363cd0-5d73-ffe8-ef40-1179806affbb.png)

消えました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/d528b24e-c9dd-dac4-6737-d029d7d35adf.png)


さらにテストを
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/433c6a39-1acf-5b7c-9df4-d796a7742e1c.png)

tama２はパスが通ってない状態、
tama1の２個目はパスが生きてる状態。
この状態で実行すると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/ecd33876-1bab-80a0-373f-e0d93891c790.png)

両方消えてしまいました。

修正
--

これの原因はここにあります。
```python
allFilePath = cmds.file(q =True ,reference =True)
```
fileコマンドで取得したファイルパスを見てみると

```
# Result: ['C:/Users/kubo/Desktop/test/tama.ma', 'C:/Users/kubo/Desktop/test/tama.ma{1}', 'C:/Users/kubo/Desktop/test/tama2.ma'] # 
```

同一のリファレンス元から読んだ場合、区別するために {n} が末尾につきます。
この状態で　os.path.exists() で存在を問い合わせると　Falseが帰ってきてしまいます。
なので、この部分を解決するためにreferenceQueryを使用して元のファイル名を問い合わせます。

```
cmds.referenceQuery(referenceNode,filename=True,withoutCopyNumber =True)
```

```python
import maya.cmds as cmds
import os
allFilePath = cmds.file(q =True ,reference =True)

for filePath in allFilePath:
    referenceNode = cmds.file(filePath,q =True ,referenceNode = True)
    loadState = cmds.referenceQuery(referenceNode,isLoaded=True)

    rawFilePath = cmds.referenceQuery(referenceNode,filename=True,withoutCopyNumber =True)
    
    if os.path.exists(rawFilePath):
        continue
        
    if loadState == False:
        cmds.file(filePath, removeReference=True)

```

これで先ほどの状態で試してみると、パスが切れているリファレンスだけを除去できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/5ee41290-69da-7395-2808-983a29209942.png)