|
@@ -0,0 +1,269 @@
|
|
|
|
+/*
|
|
|
|
+ * Copyright (C) 2021 iZc
|
|
|
|
+ *
|
|
|
|
+ * This program is free software: you can redistribute it and/or modify
|
|
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
|
|
+ * the Free Software Foundation, either version 3 of the License, or
|
|
|
|
+ * (at your option) any later version.
|
|
|
|
+ *
|
|
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
+ * GNU General Public License for more details.
|
|
|
|
+ *
|
|
|
|
+ * You should have received a copy of the GNU General Public License
|
|
|
|
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
+ */
|
|
|
|
+package de.nplusc.izc.izpl.plugins.discord;
|
|
|
|
+
|
|
|
|
+import de.nplusc.izc.iZpl.API.IZPLApi;
|
|
|
|
+import de.nplusc.izc.iZpl.API.PlayListEditAPI;
|
|
|
|
+import de.nplusc.izc.iZpl.API.shared.InvalidPlayListFileException;
|
|
|
|
+import de.nplusc.izc.iZpl.API.shared.PlayListItem;
|
|
|
|
+import de.nplusc.izc.iZpl.Utils.shared.PLFileIO;
|
|
|
|
+import de.nplusc.izc.tools.IOtools.FileTK;
|
|
|
|
+import de.nplusc.izc.tools.baseTools.Tools;
|
|
|
|
+import java.awt.EventQueue;
|
|
|
|
+import java.io.File;
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
+import java.util.List;
|
|
|
|
+import java.util.Queue;
|
|
|
|
+import java.util.concurrent.ConcurrentLinkedQueue;
|
|
|
|
+import jnafilechooser.api.JnaFileChooser;
|
|
|
|
+import org.apache.logging.log4j.LogManager;
|
|
|
|
+import org.apache.logging.log4j.Logger;
|
|
|
|
+import org.apache.logging.log4j.io.IoBuilder;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ *
|
|
|
|
+ * @author iZc <nplusc.de>
|
|
|
|
+ */
|
|
|
|
+public class UI extends javax.swing.JFrame
|
|
|
|
+{
|
|
|
|
+ private static final Logger l = LogManager.getLogger();
|
|
|
|
+
|
|
|
|
+ private int filesDone = 0;
|
|
|
|
+
|
|
|
|
+ private Discord discord;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Creates new form UI
|
|
|
|
+ */
|
|
|
|
+ public UI(Discord instance)
|
|
|
|
+ {
|
|
|
|
+ discord = instance;
|
|
|
|
+ initComponents();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * This method is called from within the constructor to
|
|
|
|
+ * initialize the form.
|
|
|
|
+ * WARNING: Do NOT modify this code. The content of this method is
|
|
|
|
+ * always regenerated by the Form Editor.
|
|
|
|
+ */
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
+ // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
|
|
|
+ private void initComponents()
|
|
|
|
+ {
|
|
|
|
+
|
|
|
|
+ btnConvert = new javax.swing.JButton();
|
|
|
|
+ gotoPlaybackView = new javax.swing.JButton();
|
|
|
|
+ baseUrl = new javax.swing.JTextField();
|
|
|
|
+ jLabel1 = new javax.swing.JLabel();
|
|
|
|
+ outputFolder = new javax.swing.JTextField();
|
|
|
|
+ jLabel2 = new javax.swing.JLabel();
|
|
|
|
+ btnChoosePath = new javax.swing.JButton();
|
|
|
|
+ progressConvert = new javax.swing.JProgressBar();
|
|
|
|
+
|
|
|
|
+ setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
|
|
|
|
+
|
|
|
|
+ btnConvert.setText("Convert for upload");
|
|
|
|
+ btnConvert.addActionListener(new java.awt.event.ActionListener()
|
|
|
|
+ {
|
|
|
|
+ public void actionPerformed(java.awt.event.ActionEvent evt)
|
|
|
|
+ {
|
|
|
|
+ btnConvertActionPerformed(evt);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ gotoPlaybackView.setText("Playback!");
|
|
|
|
+
|
|
|
|
+ jLabel1.setText("Base URL");
|
|
|
|
+
|
|
|
|
+ jLabel2.setText("Output folder");
|
|
|
|
+
|
|
|
|
+ btnChoosePath.setText("Choose");
|
|
|
|
+ btnChoosePath.addActionListener(new java.awt.event.ActionListener()
|
|
|
|
+ {
|
|
|
|
+ public void actionPerformed(java.awt.event.ActionEvent evt)
|
|
|
|
+ {
|
|
|
|
+ btnChoosePathActionPerformed(evt);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
|
|
|
+ getContentPane().setLayout(layout);
|
|
|
|
+ layout.setHorizontalGroup(
|
|
|
|
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
|
|
+ .addGroup(layout.createSequentialGroup()
|
|
|
|
+ .addComponent(gotoPlaybackView)
|
|
|
|
+ .addGap(0, 0, Short.MAX_VALUE))
|
|
|
|
+ .addGroup(layout.createSequentialGroup()
|
|
|
|
+ .addContainerGap()
|
|
|
|
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
|
|
+ .addComponent(baseUrl)
|
|
|
|
+ .addGroup(layout.createSequentialGroup()
|
|
|
|
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
|
|
|
+ .addComponent(btnConvert)
|
|
|
|
+ .addComponent(jLabel1)
|
|
|
|
+ .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
|
|
+ .addGroup(layout.createSequentialGroup()
|
|
|
|
+ .addComponent(outputFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 268, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
|
|
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
|
|
+ .addComponent(btnChoosePath, javax.swing.GroupLayout.PREFERRED_SIZE, 106, javax.swing.GroupLayout.PREFERRED_SIZE))
|
|
|
|
+ .addComponent(progressConvert, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
|
|
|
+ .addGap(0, 8, Short.MAX_VALUE)))
|
|
|
|
+ .addContainerGap())
|
|
|
|
+ );
|
|
|
|
+ layout.setVerticalGroup(
|
|
|
|
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
|
|
+ .addGroup(layout.createSequentialGroup()
|
|
|
|
+ .addGap(18, 18, 18)
|
|
|
|
+ .addComponent(jLabel1)
|
|
|
|
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
|
|
+ .addComponent(baseUrl, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
|
|
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 47, Short.MAX_VALUE)
|
|
|
|
+ .addComponent(gotoPlaybackView)
|
|
|
|
+ .addGap(18, 18, 18)
|
|
|
|
+ .addComponent(jLabel2)
|
|
|
|
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
|
|
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
|
|
|
+ .addComponent(outputFolder, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
|
|
+ .addComponent(btnChoosePath))
|
|
|
|
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
|
|
+ .addComponent(btnConvert)
|
|
|
|
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
|
|
+ .addComponent(progressConvert, javax.swing.GroupLayout.PREFERRED_SIZE, 34, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
|
|
+ .addGap(14, 14, 14))
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ pack();
|
|
|
|
+ }// </editor-fold>//GEN-END:initComponents
|
|
|
|
+
|
|
|
|
+ private void btnChoosePathActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_btnChoosePathActionPerformed
|
|
|
|
+ {//GEN-HEADEREND:event_btnChoosePathActionPerformed
|
|
|
|
+
|
|
|
|
+ JnaFileChooser fc = new JnaFileChooser();
|
|
|
|
+ fc.setMode(JnaFileChooser.Mode.Directories);
|
|
|
|
+ if (fc.showOpenDialog(this)) {
|
|
|
|
+ File f = fc.getSelectedFile();
|
|
|
|
+ outputFolder.setText(f.getPath());
|
|
|
|
+ }
|
|
|
|
+ }//GEN-LAST:event_btnChoosePathActionPerformed
|
|
|
|
+
|
|
|
|
+ private void btnConvertActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_btnConvertActionPerformed
|
|
|
|
+ {//GEN-HEADEREND:event_btnConvertActionPerformed
|
|
|
|
+ new Thread(()->
|
|
|
|
+ {
|
|
|
|
+ String outputPath = outputFolder.getText();
|
|
|
|
+ if(!outputPath.isEmpty())
|
|
|
|
+ {
|
|
|
|
+ FileTK.ensuredirExistence(outputPath+"\\x");
|
|
|
|
+ String izpl = PlayListEditAPI.getCurrentPlaylist();
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ List<PlayListItem> files = PLFileIO.parseFullList(izpl);
|
|
|
|
+ final List<String[]> commands = new ArrayList<>();
|
|
|
|
+ files.forEach(itm->
|
|
|
|
+ {
|
|
|
|
+ long size = new File(itm.getPath()).length();
|
|
|
|
+ if(size>0)
|
|
|
|
+ {
|
|
|
|
+ String targetfilename = PlayListEditAPI.getTitle(itm);
|
|
|
|
+ String folderHash = discord.hashFilename(size, targetfilename);
|
|
|
|
+ String resultFile = outputPath+"\\"+folderHash+"\\"+targetfilename+".mp3";
|
|
|
|
+ FileTK.ensuredirExistence(resultFile);
|
|
|
|
+ String[] cmd =
|
|
|
|
+ {
|
|
|
|
+ IZPLApi.PLUGINPATH+File.separator+"DiscordJukebox"+File.separator+"binaries"+File.separator+"ffmpeg.exe",
|
|
|
|
+ "-i",
|
|
|
|
+ itm.getPath(),
|
|
|
|
+ "-vn",
|
|
|
|
+ "-ar",
|
|
|
|
+ "44100",
|
|
|
|
+ "-ac",
|
|
|
|
+ "2",
|
|
|
|
+ "-b:a",
|
|
|
|
+ "192k",
|
|
|
|
+ resultFile
|
|
|
|
+ };
|
|
|
|
+ commands.add(cmd);
|
|
|
|
+ // ffmpeg -i input.wav -vn -ar 44100 -ac 2 -b:a 192k output.mp3
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ Queue<String[]> commandsToRun = new ConcurrentLinkedQueue<String[]>(commands);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ progressConvert.setMaximum(commands.size());
|
|
|
|
+ progressConvert.setValue(0);
|
|
|
|
+ Runnable r = ()->
|
|
|
|
+ {
|
|
|
|
+ String[] cmd = commandsToRun.poll();
|
|
|
|
+ while(cmd!=null)
|
|
|
|
+ {
|
|
|
|
+ Tools.runCmdWithPassthru(
|
|
|
|
+ IoBuilder.forLogger("External.FFMpeg").buildPrintStream(),
|
|
|
|
+ cmd);
|
|
|
|
+ synchronized(discord)
|
|
|
|
+ {
|
|
|
|
+ filesDone++;
|
|
|
|
+ EventQueue.invokeLater(()->
|
|
|
|
+ {
|
|
|
|
+ progressConvert.setValue(filesDone);
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ cmd = commandsToRun.poll();
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ Thread[] processingthreads = new Thread[8];
|
|
|
|
+ for(int i=0;i<8;i++)
|
|
|
|
+ {
|
|
|
|
+ Thread t = new Thread(r, "WPC-Worker-"+i);
|
|
|
|
+ processingthreads[i] = t;
|
|
|
|
+ t.start();
|
|
|
|
+ }
|
|
|
|
+ for(int i=0;i<8;i++)
|
|
|
|
+ {
|
|
|
|
+ try{
|
|
|
|
+ processingthreads[i].join();
|
|
|
|
+ }
|
|
|
|
+ catch(InterruptedException e)
|
|
|
|
+ {
|
|
|
|
+
|
|
|
|
+ };
|
|
|
|
+ }
|
|
|
|
+ EventQueue.invokeLater(()->
|
|
|
|
+ {
|
|
|
|
+ progressConvert.setValue(filesDone);
|
|
|
|
+ });
|
|
|
|
+ l.info("Multithreaded processing finished");
|
|
|
|
+ }
|
|
|
|
+ catch (InvalidPlayListFileException ex)
|
|
|
|
+ {
|
|
|
|
+ ex.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }).start();
|
|
|
|
+ }//GEN-LAST:event_btnConvertActionPerformed
|
|
|
|
+
|
|
|
|
+ // Variables declaration - do not modify//GEN-BEGIN:variables
|
|
|
|
+ private javax.swing.JTextField baseUrl;
|
|
|
|
+ private javax.swing.JButton btnChoosePath;
|
|
|
|
+ private javax.swing.JButton btnConvert;
|
|
|
|
+ private javax.swing.JButton gotoPlaybackView;
|
|
|
|
+ private javax.swing.JLabel jLabel1;
|
|
|
|
+ private javax.swing.JLabel jLabel2;
|
|
|
|
+ private javax.swing.JTextField outputFolder;
|
|
|
|
+ private javax.swing.JProgressBar progressConvert;
|
|
|
|
+ // End of variables declaration//GEN-END:variables
|
|
|
|
+}
|