Vue+flaskで動画合成機能を実現(ドラッグ&ドロップアップロード)

Vue+flaskで動画合成機能を実現(ドラッグ&ドロップアップロード)

vue+flaskで実現したビデオ合成効果は以下のとおりです

ここに画像の説明を挿入

ドラッグアンドドロップアップロードについては以前の記事で書きました。

//www.jb51.net/article/206543.htm

原理は、ドロップイベントをリッスンしてドラッグされたファイルリストを取得することです。

ここに画像の説明を挿入
ここに画像の説明を挿入

ファイルをアップロードする

axios経由でファイルをアップロードする

this.fileListはファイルリストです

ファイルを this.fileList とします。
formd = new FormData();
i = 1 とします。

//アップロードリストファイルを追加します。forEach(item => {
	formd.append(i + "", 項目、項目名)
	私は++;
})
formd.append("type", i)
設定 = {
	ヘッダー: {
		「コンテンツタイプ」: 「マルチパート/フォームデータ」
	}
}

//ファイルアップロードリクエスト axios.post("/qwe", formd, config).then(res => {
	コンソールログ(res.data)
})

Flaskはファイルを処理する

完全なコードは下部をご覧ください

ロジックは次のとおりです。ファイルを受信し、合成要求ごとにフォルダーをランダムに生成し、ファイルを一時的に保存し、ビデオをステッチし、ファイルパスを返します。

@app.route("/file",メソッド=['POST'])
デフテスト():

 #ファイルを取得する files = request.files
 #合成キュー videoL = []
 #ランダム文字列 dirs = sjs()
 #フォルダーを生成 os.mkdir(dirs)
 #ファイルを保存し、files.values() 内のファイルの合成キューに追加します。
  印刷(ファイル)
  dst = dirs + "/" + ファイル名 + ".mp4"
  ファイル.save(dst)
  ビデオ = VideoFileClip(dirs + "/" + ファイル名 + ".mp4")
  videoL.append(ビデオ)
 
 #ビデオを結合 final = concatenate_videoclips(videoL)
 #ファイルパス fileName = dirs + "/" + "{}.mp4".format(sjs())
 #ビデオを生成する final.to_videofile(fileName)
 
 #フォルダーを破棄 def sc():
  shutil.rmtree(ディレクトリ)
 
 #30秒後にフォルダーを破棄します timer = threading.Timer(30, sc)
 タイマー.開始()

 # ファイルパスを返す return fileName

ファイルパスを取得するためのスプライシング

まずフラスコを見てみましょう

ロジックは次のとおりです。ファイル名でファイルを取得し、ファイルを返します。

app.route("/getvoi",メソッド=['GET'])
getImg() を定義します:
 #ファイル名を取得する ss = request.args['name']
 #返されたレスポンスにファイルを追加する response = make_response(
  送信ファイル

 #ファイルを削除する def sc():
  os.remove(ss)
 
 #30秒後にファイルを削除します timer = threading.Timer(30, sc)
 タイマー.開始()
 
 応答を返す

フロントエンドの獲得

タグaでダウンロード

<as :href="herfs" rel="external nofollow" rel="external nofollow" :download="fileName">ダウンロード</a>

ハーフは以下の通りです

ここに画像の説明を挿入

ファイルをアップロードした後、返されたファイルパスをfalskで処理し、ファイルアドレスを取得します。

aタグにダウンロード属性を追加すると、ダウンロードしたファイルに名前を付けることができます。

/qwe /voiについてご質問がある場合は、次のプロキシ設定手順を参照してください。

プロキシ設定手順

プロキシを設定する目的は、クロスドメインの問題を解決することです。開発環境はvue.config.jsで設定して使用できます。本番環境ではnginxの追加設定が必要です。

ここに画像の説明を挿入

/qwe は実際には http://127.0.0.1:8087/file です
/voi は実際には http://127.0.0.1:8087/getvoi です
フラスコに対応

ここに画像の説明を挿入

追加メモ(uni-app を使用する場合)

uni-appを使用する場合は、APIを使用するためのドキュメントを参照してください。
ファイルアップロード API https://uniapp.dcloud.io/api/request/network-file?id=uploadfile
ファイルのダウンロード API https://uniapp.dcloud.io/api/request/network-file?id=downloadfile
または、他の人がパッケージ化したプラグインを直接使用する方が便利です。

完全なコード

一つずつコピーしたくない場合は、ダウンロード パス 1 からダウンロードできます: https://download.csdn.net/download/qq_42027681/15561897
ダウンロードパス 2: https://github.com/dmhsq/vue-flask-videoSynthesis

フラスココード

md5random.pyはランダムな文字列を生成するために使用されます

ランダムにインポート
ハッシュライブラリをインポートする
sjs() を定義します:
 a = ランダム.randint(0, 100)
 a = "a" + str(a);
 100 から 10000 までの整数をランダムに計算します。
 b = "b" + str(b);
 c = hashlib.md5(a.encode(encoding='UTF-8')).hexdigest() + hashlib.md5(b.encode(encoding='UTF-8')).hexdigest();
 c = "c" + str(c);
 d = ランダム.randint(10, 100);
 d = "d" + str(d);
 e = hashlib.md5(c.encode(encoding='UTF-8')).hexdigest() + hashlib.md5(d.encode(encoding='UTF-8')).hexdigest();
 e = hashlib.md5(e.encode(encoding='UTF-8')).hexdigest()
 e を返します。

app_service.py サービスコード

Flask から Flask、request、send_file、make_response をインポートします
os、json、threading、shutil をインポートします
moviepy.editor からインポート *
md5randomからsjsをインポート

アプリ = Flask(__name__)

@app.route("/file",メソッド=['POST'])
デフテスト():

 #ファイルを取得する files = request.files
 #合成キュー videoL = []
 #ランダム文字列 dirs = sjs()
 #フォルダーを生成 os.mkdir(dirs)
 #ファイルを保存し、files.values() 内のファイルの合成キューに追加します。
  印刷(ファイル)
  dst = dirs + "/" + ファイル名 + ".mp4"
  ファイル.save(dst)
  ビデオ = VideoFileClip(dirs + "/" + ファイル名 + ".mp4")
  videoL.append(ビデオ)

 #ビデオを結合 final = concatenate_videoclips(videoL)
 #ファイルパス fileName = dirs + "/" + "{}.mp4".format(sjs())
 #ビデオを生成する final.to_videofile(fileName)

 #フォルダーを破棄 def sc():
  shutil.rmtree(ディレクトリ)

 #30秒後にフォルダーを破棄します timer = threading.Timer(30, sc)
 タイマー.開始()

 # ファイルパスを返す return fileName


@app.route("/getvoi",メソッド=['GET'])
getImg() を定義します:
 #ファイル名を取得する ss = request.args['name']
 #返されたレスポンスにファイルを追加する response = make_response(
  送信ファイル

 #ファイルを削除する def sc():
  os.remove(ss)

 #30秒後にファイルを削除します timer = threading.Timer(30, sc)
 タイマー.開始()

 応答を返す

__name__ == '__main__' の場合:
 app.run(ホスト='0.0.0.0'、ポート=8087)

vueコード

デモファイルコード

<テンプレート>
 <div>
 <div
  v-on:dragover="tts"
  v-on:drop="ttrs"
  スタイル="幅: 800px;高さ: 200px;境界線: 1px 黒一色;フォントサイズ: 40px;行の高さ: 200px"
 >
  {{dt}}
 </div>
 <div
  v-for="(item, index) in fileList"
  :key="インデックス"
  スタイル="幅: 800px;高さ: 200px;境界線: 1px 黒一色;フォントサイズ: 40px;位置: 相対;上: 10px"
 >
  <p
  style="font-size: 20px;float: left;position: relative;left: 20pxword-wrap:break-word;word-break:normal;"
  >
  {{アイテム名}}
  </p>
  <h5 style="float:right;position: absolute;top: 80px;right: 20px">
  {{アイテムタイプ}}
  </h5>
  <h6 スタイル="位置: 絶対;上: 80px;フロート: 左;左: 20px">
  {{ item.size | サイズタイプ }}
  </h6>
  <button style="float: right" @click="del(index)">削除</button>
 </div>
 <!-- ここには最後にアップロードされたファイルが表示されます-->
<!-- <div style="position:relative;top: 100px">-->
<!-- <img v-if="isImage" :src="srcs" style="width: 800px" />-->
<!-- <video v-if="isVideo" controls :src="srcs" style="width: 800px"></video>-->
<!-- <audio v-if="isAudio" controls :src="srcs" style="width: 800px"></audio>-->
<!-- </div>-->

 <el-button style="position: relative;top: 50px" type="success" @click="ups()" :disabled="!isCan">合成</el-button>
 <el-button style="position: relative;top: 50px" v-loading="loading" type="success" >。 。 。 </el-button>
 <a style="position: relative;top: 50px;left: 15px;" type="success" :href="herfs" rel="external nofollow" rel="external nofollow" :download="fileName"><el-button :disabled="isCans"><span style="color: black">ダウンロード</span></el-button></a>
 <div style="position: relative;top: 100px">ファイルのダウンロード有効時間 {{times}} 秒</div>
 </div>
</テンプレート>

<スクリプト>
「axios」からaxiosをインポートします。

エクスポートデフォルト{
 名前: "trs",
 データ() {
 戻る {
  dt: "", // アップロードリマインダー「ファイルをアップロードするにはここにドラッグしてください」または「アップロードが完了しました。アップロードを続行できます」
  fileList: [], // ファイルリストの読み込み: false,
  srcs: "", //画像/ビデオ/オーディオ base64
  isImage: false, //画像ですか? isAudio: false, //音声ですか? isVideo: false, //動画ですか? isCan: true, //合成できますか? isCans: true, //ダウンロードできますか? herfs: "", //ダウンロードアドレス fileName: "", //ファイル名 times: 25 //ダウンロード有効期間 };
 },
 フィルター:
 //ファイルサイズのフォーマット sizeType(val) {
  kbs = val / 1024とします。
  mbs = 0 とします。
  gbs = 0 とします。
  (kbs >= 1024)の場合{
  mbs = kbs / 1024;
  }
  mbs >= 1024の場合{
  gbs = mbs / 1024;
  gbs.toFixed(2) + "GB" を返します。
  } それ以外の場合 (mbs >= 1) {
  mbs.toFixed(2) + "MB"を返します。
  } それ以外 {
  kbs.toFixed(2) + "KB"を返します。
  }
 }
 },
 マウント() {
 vm = this とします。
 window.addEventListener("dragdrop", this.testfunc, false);

 //ページ内にファイルドラッグリマインダーがあるときのグローバル監視ここにドラッグ document.addEventListener("dragover", function() {
  コンソールログ(111);
  vm.dt = "ファイルをアップロードするにはここにドラッグしてください";
  コンソールログ(vm.dt);
 });
 },
 メソッド: {
 //表示ファイルは主に画像/ビデオ/オーディオの3種類です。readFile(file) {
  vm = this とします。
  リーダーを新しいFileReader()にします。
  reader.readAsDataURL(ファイル);
  リーダー.onload = 関数() {
  type = file.type.substr(0, 5); とします。
  if (type == "画像") {
   vm.isImage が true である。
   vm.isAudio = false;
   vm.isVideo = false;
  } そうでない場合 (type == "audio") {
   vm.isImage = false;
   vm.isAudio が true である。
   vm.isVideo = false;
  } そうでない場合 (type == "video") {
   vm.isImage = false;
   vm.isAudio = false;
   vm.isVideo が true である。
  } それ以外 {
   alert("画像/ビデオ/オーディオではありません");
  }
  vm.srcs = リーダーの結果;
  // this.$nextTick(()=>{
  //
  // })
  };
 },
 //ドロップのトリガーイベントをグローバルに監視してドロップポップアップウィンドウの表示をキャンセルするリソース testfunc(event) {
  アラート("ドラッグドロップ!");

  //ドロップポップアップウィンドウの表示リソースをキャンセルします。event.stopPropagation();
  イベントをデフォルトにしない();
 },
 del(インデックス) {
  this.fileList.splice(インデックス、1);
  if (this.fileList.length === 0) {
  this.dt = "";
  }
 },
 //div アップロード ボックスを監視し、ファイルがドラッグされたときに「ファイルをアップロードするにはここにドラッグしてください」と表示します
 tts(e) {
  コンソールログ(e);
  this.dt = "ファイルをアップロードするにはここにドラッグしてください";
 },
 //divアップロードボックスのドロップイベントをリッスンしてttrs(e)をトリガーします{
  コンソールログ(e);
  console.log(e.dataTransfer.files);

  //ファイルを取得する let datas = e.dataTransfer.files;

  //ドロップポップアップウィンドウの表示リソースをキャンセルします e.stopPropagation();
  e.preventDefault();
  datas.forEach(item => {
  if(item.type=="video/mp4"){
   this.fileList.push(アイテム);
  }
  });

  // ファイルを読み取ります。画像/ビデオ/オーディオを表示したくない場合は、this.readFile(this.fileList[this.fileList.length - 1]); を無視できます。



  this.dt = "アップロードが完了しました。アップロードを続行できます";
 },

 //サーバーにファイルをアップロードする ups(){
  if(this.fileList.length==0){
  this.$message('ファイルリストは空です');
  戻る ;
  }
  this.loading = true;
  this.isCan = false;
  this.isCans = true;
  ファイルを this.fileList とします。
  formd = new FormData();
  i = 1 とします。

  //アップロードリストファイルを追加します。forEach(item=>{
  formd.append(i+"",item,item.name)
  私は++;
  })
  formd.append("type",i)
  config={を設定します
  ヘッダー:{"Content-Type":"multipart/form-data"}
  }

  //ファイルアップロードリクエスト axios.post("/qwe",formd,config).then(res=>{
  コンソールログ(res.data)
  this.loading = false
  //合成ダウンロードパス this.herfs = "/voi?name="+res.data

  this.fileName = res.data.split('/')[1]
  //合成は禁止されています this.isCan = false

  this.isCans = false

  //ダウンロードの有効期間を設定します。時間が経過するとダウンロードは完了できなくなりますが、合成は続行できます。let timer = setInterval(()=>{
   今回は--;
  },1000)
  this.setCans(タイマー)
  })
 },
 setCans(タイマー){
  タイムアウトを設定します(()=>{
  this.isCans = true
  this.isCan = true
  this.fileName = ""
  クリアインターバル(タイマー)
  これを25回繰り返す
  },25000)
 }
 }
};
</スクリプト>

<スタイル スコープ></style>

設定ファイル

モジュール.エクスポート = {
 開発サーバー: {
 // アセットサブディレクトリ: 'static',
 // アセットパブリックパス: '/',
 プロキシ: {
  "/qwe": {
  ターゲット: "http://127.0.0.1:8087/file",
  変更元: true、
  パス書き換え: {
   "^/qwe": ""
  }
  },
  "/voi": {
  ターゲット: "http://127.0.0.1:8087/getvoi",
  変更元: true、
  パス書き換え: {
   "^/voi": ""
  }
  }
 }
 }
};

これで、vue+flask で動画合成機能 (ドラッグアンドドロップアップロード) を実現する方法についての説明は終わりです。vue 動画合成に関するその他の関連コンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Vueはドラッグアンドドロップまたはクリックで写真をアップロードする機能を実装しています
  • Vue2をベースにモバイル画像アップロード、圧縮、ドラッグアンドドロップソート、ドラッグアンドドロップ削除機能を実現
  • Vue3 ベースのフルスクリーン ドラッグ アップロード コンポーネント

<<:  Win10 システムに MySQL8.0.13 をインストールする際の問題と解決策

>>:  MySQL v5.7.18 解凍バージョンのインストール詳細チュートリアル

推薦する

シンプルな画像ドラッグ効果を実現する js

この記事では、簡単な画像ドラッグ効果を実現するためのjsの具体的なコードを参考までに紹介します。具体...

Linux でのインストール中にソフトウェア パッケージの依存関係レポートに関連する問題の解決策

目次背景1) yumのkeepchche機能を有効にする: 方法1 2) yum-utils ソフト...

ウェブデザインにおける円形要素の使用例 25 選

本日の投稿では、Web デザインで使用される円形要素の優れた例をいくつか挙げ、美しい丸いボタン、メニ...

MySql 5.7.17 winx64 のインストールと設定に関する詳細なチュートリアル

1. ソフトウェアをダウンロードする1. MySQL の公式サイトにアクセスし、Oracle アカウ...

MySQL がデータの削除と挿入に非常に時間がかかる問題の解決策

会社の開発者がテスト環境で挿入ステートメントを実行すると、正常に実行されるまでに 10 秒以上かかり...

Nginx rtmp モジュールのコンパイル ARM バージョンの問題

目次1. 準備: 2. ソースコードのコンパイル1. 設定する2. コンパイルエラー3. ターゲット...

UbuntuでGRUBの起動時間を変更する

grubの起動時間を変更するためのオンライン検索は基本的に/etc/default/grubを変更す...

CentOS のファイルと権限の基本操作チュートリアル

序文始める前に、ファイル属性とファイル属性を変更する方法について簡単に理解しておく必要があります。 ...

マインスイーパゲームを実装するための jQuery プラグイン (1)

この記事では、jQueryプラグインを使用したマインスイーパゲームの最初の記事の具体的なコードを参考...

Vueは物流タイムライン効果を実現します

この記事では、物流タイムライン効果を実現するためのVueの具体的なコードを例として紹介します。具体的...

Vue で親子コンポーネントの値を双方向バインドするために v-model を使用するときに発生する問題と解決策

目次シナリオ解決してみる解決するシナリオ今日、コンポーネントの双方向データバインディングにv-mod...

Jupyter Notebook で JavaScript を実行する方法

その後、VSC で Jupyter Notebook を使用する方法も追加しました...アナコンダを...

ReactプロジェクトにSCSSを導入する方法

まず依存関係をダウンロードします yarn sass-loader ノード sass を追加します次...

1つのSQL文でMySQLの重複排除が完了し、1つが保持されます。

数日前、ある要件に取り組んでいたとき、MySQL で重複レコードをクリーンアップする必要がありました...

Vueはビデオ再生を実装するためにビデオタグを使用します

この記事では、ビデオタグを使用してビデオ再生を実装するVueの具体的なコードを参考までに共有します。...