2017年5月2日 星期二

Wine 利用 winepath 轉換 linux 系統上檔案位置到 Wine 系統上使用

為了要用滑鼠拖拉(drag and drop)的方式開啟檔案,首先執行檔要能接收檔案,若是用 bash script 可以使用 $1 接收第一個參數,經由命令變數 $(winepath -w %1)可以轉換給 Wine 應用程式使用.而使用副檔名 .desktop 的執行檔則可以用  %f 來接收滑鼠傳來的檔案位置,同樣也是利用命令變數 $(winepath -w %f) 轉換給 Wine 應用程式加以使用.類似像這樣:
[Desktop Entry]
Exec=env  WINEPREFIX=/home/mint/.wine  wine  'c:\\windows\\notepad.exe' $(winepath -w %f)
Type=Application

記得將它存檔並設定為可執行檔,這樣就可以利用滑鼠拖拉檔案到該執行擋上,Wine 應用程式就可以從滑鼠接收到檔案接著轉換檔案位置,最後在 Wine 系統中開啟檔案.

當然如果有建立 mswin  群組,並將 mint 加入該群組, 透過切換群組開啟檔案,只要將上述檔案稍微修改一下改用 sg 命令:
[Desktop Entry]
Exec=sg mswin "env  WINEPREFIX=/home/mint/.wine  wine  'c:\\windows\\notepad.exe' $(winepath -w %f)"
Type=Application

 Wine 已更新到 2.7 版了, 參考網站: https://wiki.winehq.org/Ubuntu

sudo dpkg --add-architecture i386
wget https://dl.winehq.org/wine-builds/Release.key
sudo apt-key add Release.key
sudo apt-add-repository 'deb https://dl.winehq.org/wine-builds/ubuntu/ xenial main'
sudo apt-get update
sudo apt-get install --install-recommends winehq-staging

2017年5月1日 星期一

避免 Wine 的應用程式開啟網路

參考文章: https://askubuntu.com/questions/19346/how-to-block-internet-access-for-wine-applications
有些 windows 應用程式太邪惡了, 許多病毒或是木馬甚至原版軟體都有可能偷偷上網傳遞資訊,使用者根本無法察覺,如果將它安裝成 Wine 的應用程式想必也不例外,因此有必要限制 Wine 的網路行為.在 linux mint 可以用 groupadd 產生新的群組,用 adduser 將使用者加入這新的群組,再透過 iptables 阻斷群組的網路行為:
       sudo groupadd  mswin
       sudo adduser  mint  mswin
       sudo iptables  -A  OUTPUT  -m  owner  --gid-owner  mswin  -j  REJECT

往後只要用 sg 先切換使用群組,之後才載入 Wine 的應用程式(例如內建瀏覽器 wine iexplore.exe),這樣就能徹底隔絕 Wine 應用程式的網路運作了.
       sg  mswin  "wine iexplore.exe"

如果要用滑鼠雙擊就可執行的 Wine 應用程式,可以編輯一個檔案副檔名用 .desktop 命名, Exec 指定內容則改用 linux 的 sg 切換群組並包住 env 命令,像這樣:
[Desktop Entry]
Exec=sg mswin "env  WINEPREFIX=/home/mint/.wine  wine  'c:\\windows\\notepad.exe'"
Type=Application

要注意的是 env 命令的部份要用引號括起來. 在 wine 的應用程式敘述用單引號而整個 env 部份則改用雙引號.單引號與雙引號的不同在於:單引號裡面內容,如果有$變數或執行()命令或者跳脫字元\時,並不會展開賦值(evaluate),而是一成不變的照實敘述,但如果放在雙引號裡面則會先展開變數才會執行後續動作.記憶口訣: 一層不變(一成不變), 二度就要(二度就樂一ㄠˋ)

2017年4月30日 星期日

執行備份的 wine 應用程式

安裝完 wine 的應用程式後,預設全都會放在 ~/.wine 底下, 可以先切換到家目錄(~)再將 .wine 目錄打包備份,之後把 wine.tgz 移至別處加以收藏,在終端機輸入以下命令將 .wine 打包:
       cd  ~
       tar  -zcvf  wine.tgz  .wine

如果有任何意外破壞了 .wine 的目錄結構,可以先刪掉該目錄(rm -rf .wine)再藉由回存指令(tar  -zxvf wine.tgz), 就可以恢復該目錄所有檔案,並不需要將應用程式重頭安裝.至於剛安裝完 wine 執行 winecfg 時,一開始會要求從網路下載穩定版本的 gecko 及 mono, 但使用備份檔的好處是因為先前已安裝過並備份到 wine.tgz 裡面了, 因此不用再從網路下載資源浪費時間.假設 /path_to 是 wine.tgz 想要解壓縮之位置,而 /path_from 是備份檔案 wine.tgz 所收藏之地方,在終端機輸入以下命令,用打包的檔案還原檔案:
        sudo  mkdir   /path_to
        sudo  chown  mint   /path_to
        cd   /path_to
        tar  -zxvf   /path_from/wine.tgz

如果 .wine 的目錄不是放在家目錄(~/.wine)底下,可以透過 linux 的 env 命令(設定環境變數並執行後續命令,相關用法使用 man env 就可以瞭解),先將環境變數 WINEPREFIX 指向 .wine 所在的位置,接著用 wine去 載入應用程式來執行.想要執行 windows 內建的 notepad.exe,在終端機輸入:
        env  WINEPREFIX="/path_to/.wine"   wine    "c:\\windows\\notepad.exe"

如果覺得用 env 執行命令很繁瑣,也可以先切換到家目錄(~), 再用符號連結(symbolic link)的方式去建立連結,在終端機輸入命令:
        cd  ~
        ln   -sf   /path_to/.wine    .wine

之後在終端機用 wine 就可以載入應用程式並執行:
      wine    "c:\\windows\\notepad.exe"

另外用 wine regedit 去手動設定 windows 的內建環境變數, 可以在裡面添加 path:
       REGEDIT4

       [HKEY_CURRENT_USER\Environment]
       "path"="%path%;c:\windows"

或將上述內容存成 winenv.reg 檔案, 在終端機輸入 wine regedit 檔名,把要註冊的內容放進 windows 環境變數內:
       wine regedit  winenv.reg

往後就不用再打一長串的路徑,直接在終端機用 wine 載入應用程式,windows 會自動用 path 所指定的目錄去找尋執行檔來執行,因此要執行內建的 notepad.exe 只要在終端機輸入 :
      wine notepad

在 linux mint上有更直接的用法,去編輯一個檔案,將副檔名以 .desktop 命名,在桌面進入點的段落 [Desktop Entry] 敘述中包含 Exec 及 Type 這兩個關鍵字,其中 Exec 讓它等於上述 linux 的 env 命令,將需要執行 wine 程式的相關參數隨後填入,而 Type 則直接等於 Application 這個字, 類似像這樣:
     [Desktop Entry]
     Exec=env  WINEPREFIX="/home/mint/.wine"  wine  "c:\\windows\\notepad.exe"
     Type=Application

將它存檔,先隨便取個名字(例如 notepad.desktop), 之後用滑鼠右鍵將它改成中文名,要執行時只要用滑鼠左鍵雙擊該檔案就能直接執行,相當方便.

2017年4月23日 星期日

用 nodejs 內建的 Promise 語法執行 child_process 外部程式 ffmpeg


定義 function ffmpeg,記得要將可執行檔 ffmpeg 放在目前目錄底下:
1. 這是原始function的定義,傳進來參數命名為 options,  檔名: child.js
      function ffmpeg(options) {
          const child = require('child_process');    // 調用內建child_process程式庫
          var cmd =__dirname+'/ffmpeg ' + options;   // 傳給child_process 時所需要的參數
          child.exec(cmd,function (err, stdout, stderr) { // child_proces開始處理指令
                  if( err )   console.log('出錯了:'+err+'\nstderr:'+stderr);
                  else       console.log('成功了:'+stdout);
           });  // end child_process
       } // end of ffmpeg
       ffmpeg('-version'); // 呼叫 ffmpeg 函式:

2. 這是將上述 function ffmpeg(options )轉化成 Promise 的用法, 檔名: child.js
      function ffmpeg(options) {
           return new Promise(function (ok,ng) {//回傳 closure,將會有兩個callback function
               const child = require('child_process');
               var cmd =__dirname+'/ffmpeg ' + options;
               child.exec(cmd, function (err, stdout, stderr) {
                   if(  err )  ng('出錯了:'+err+'\nstderr:'+stderr);// 回調(callback) ng
                   else       ok('成功了:'+stdout);   // 回調(callback) ok
               }); // end child_process
           }); // end of closure
       } // end of ffmpeg
      // 轉化成 Promise,就可以呼叫 then( ) 及 catch( ), 執行指令:
       ffmpeg('-version').then(console.log).catch(console.log);
      // 其中 then( ) 裡面的 callback 對應到 ok, 而 catch( ) 裡面的 callback 對應到 ng

3.  存檔用 nodejs 執行
       js  child.js


p.s. 轉檔時, 避免操壞硬碟, 改用 RAMDISK, linux 的 ramdisk 位置在 /dev/shm, 參考範例:
    var fs = require('fs'),
    var dirRAM='/dev/shm/hls'; // create a directory in ramdisk
    fs.mkdir(dirRAM, function(err) {
        fs.symlink(dirRAM, __dirname + '/hls', function(errlink ) { // create a symbolic link
            process.chdir(__dirname + '/hls'); // enter to the directory
            ffmpeg('-i '+ __dirname + '/oceans.mp4  -hls_flags delete_segments playlist.m3u8').then(console.log).catch(console.log); // media file transcode
        })
    })

2017年4月20日 星期四

下載 ffmpeg-3.3 自行編譯,讓它支援 pthreads, librtmp, libx264, libvpx, libx265, libvorbis, libmp3lame, libass 方便轉換影音檔

1. 上官網先下載原始碼(source code) 並解壓縮:
    wget http://ffmpeg.org/releases/ffmpeg-3.3.tar.bz2
    tar -xvf ffmpeg-3.3.tar.bz2
    cd ffmpeg-3.3
或是利用 git 複製出整個 repository:
    git clone https://git.ffmpeg.org/ffmpeg.git

2. 下載編譯環所需要的標頭檔:
sudo apt-get install librtmp-dev libx264-dev libvpx-dev libx265-dev libvorbis-dev libmp3lame-dev libass-dev yasm

3. 設定環境並開始編譯:
  ./configure --enable-gpl --enable-pthreads --enable-librtmp  --enable-libx264 --enable-libvpx --enable-libx265 --enable-libvorbis --enable-libmp3lame --enable-libass
  make

4. 複製 ffmpeg 到 /usr/bin
   sudo cp ffmpeg /usr/bin


5. 一些使用 ffmpeg 的範例:
   列出 webcam 支援的格式:
       ffmpeg -f v4l2 -list_formats all -i /dev/video0
   
   讓 ffmpeg 在背景擷取 webcam 影像,轉換產生 http live streaming (HLS) 所需要的檔案:
   ffmpeg -f v4l2 -i /dev/video0 -hls_flags delete_segments playlist.m3u8

   讓 ffmpeg 在背景擷取mp4檔案,轉換產生每個ts檔大約是10秒的HLS檔案:
   ffmpeg -i oceans.mp4 -hls_time 10 playlist.m3u8

   
   架設 http live streaming server 只要架設好 http server,再將轉換完成的HLS檔案放在讓 HLS client 可以下載到的地方,一旦下載完 playlist.m3u8 就可以隨後播放裡面的ts影片擋了.

bash 變數, 錢字符號 $, ${ }, $( ), $(( )) 不同點

參考文章: http://stackoverflow.com/questions/27472540/difference-between-and-in-bash-scripting
設定 bash 的變數 var 成為一個字串, 例如:  
     var = 'This is a test'
若要將變數內容取出來,在變數名稱前面加上錢字符號 $ 就可:
     echo $var
如果變數後面有跟隨其它字元時,用大括號刮起來以便區別成變數,因此 $ 與 ${ } 是相同用法.
     echo ${var}string,  append some string behind
但 $( ) 在小括號裡的是一個指令, 會被 bash 先取出來執行,執行完的輸出就是變數內容, 簡稱指令變數, 例如:
     echo  目前目錄是:$(pwd)
用雙小括號變數可以做簡單整數的加減乘除(+-*/)四則運算,:
   echo $(( 5-19+2*3 + 3/3 ))

bash 命令列的管線

參考文章: http://stackoverflow.com/questions/24793069/what-does-do-in-bash
標準輸入(stdin)的內建編號等於 0
標準輸出(stdout)的內建編號等於 1
標準錯誤(stderr)的內建編號等於 2
語法:
1. 內建編號 >  檔案名稱    : 若忽略內建編號,指的是將標準輸出轉向到檔案名稱, 相當於:  1> 檔案名稱
2. 內建編號 &> 檔案名稱  : 若忽略內建編號,指的是將標準輸出及標準錯誤都同時轉向到檔案名稱
3. 內建編號 >& 內建編號或檔案名稱  : 若忽略內建編號,指的是將標準輸出及標準錯誤都同時轉向


至於 2 與 3 有何不同呢? 舉個例子來看,  先產生一個文字檔 t:
       echo  This is a test file > t
列出 t 及 txxx 檔案的內容, 將標準輸出轉到 a, 並將標準錯誤轉到 b
       cat t  txxxxx      1>a   2>b
再來將 t 及 txxx 檔案的內容列印出來, 管線將標準輸出及標準錯誤同時轉到檔案 c
無論用  cat  t  txxxxx  &>  c 或  cat  t  txxxxx   >&  c 都得到相同結果,但
用   cat t  txxxxx      &>  1 卻是產生一個案名稱 1, 不會輸出到螢幕上.
而   cat t  txxxxx     >&  1 則是輸出到標處準輸出(螢幕)上, 不會另外產生一個檔案.

因此要使用 &> 或 >& , 就看要輸出是新檔案還是內建編號(0,1,2), 若要輸出到一般檔案就用 &> , 若要輸出到內建編號就要另外使用 >&了.