Version 2(add Google_Service_Drive )
This commit is contained in:
parent
747c6e8a44
commit
c522954b44
|
|
@ -1,3 +1,3 @@
|
|||
/node_modules
|
||||
|
||||
config/service-account.json
|
||||
package-lock.json
|
||||
|
|
@ -1,155 +1,270 @@
|
|||
.audio-diary-admin-page {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.audio-diary-admin-page body {
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
.audio-diary-admin-page #recording-button {
|
||||
background-color: red;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 20px;
|
||||
font-size: 20px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
margin-top: 20px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-image: url('../img/microphone.png'); /* آدرس تصویر میکروفون */
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 50%;
|
||||
display: block;
|
||||
margin: 20px auto; /* برای قرارگیری در وسط صفحه */
|
||||
background-color: red;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 20px;
|
||||
font-size: 20px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
margin-top: 20px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-image: url("../img/microphone.png"); /* آدرس تصویر میکروفون */
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 50%;
|
||||
display: block;
|
||||
margin: 20px auto; /* برای قرارگیری در وسط صفحه */
|
||||
}
|
||||
|
||||
.audio-diary-admin-page #visualizer {
|
||||
display: none;
|
||||
margin-top: 20px;
|
||||
display: none;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.audio-diary-admin-page audio {
|
||||
display: none;
|
||||
margin: 20px auto;
|
||||
width: 300px;
|
||||
display: none;
|
||||
margin: 20px auto;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.audio-diary-admin-page audio.show {
|
||||
display: block;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.audio-diary-admin-page canvas {
|
||||
display: block;
|
||||
margin: 20px auto;
|
||||
border: 2px solid #c5c3c3; /* مثال: خط قرمز دور canvas */
|
||||
border-radius: 10px; /* مثال: گوشههای گرد */
|
||||
width: 100%; /* عرض 100% از والد */
|
||||
max-width: 600px; /* حداکثر عرض 600px */
|
||||
height: 100px; /* ارتفاع 100px */
|
||||
background-color: rgba(255, 255, 255, 0.1); /* مثال: زمینه نیمه شفاف سفید */
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* سایه برای دادن عمق */
|
||||
display: block;
|
||||
margin: 20px auto;
|
||||
border: 2px solid #c5c3c3; /* مثال: خط قرمز دور canvas */
|
||||
border-radius: 10px; /* مثال: گوشههای گرد */
|
||||
width: 100%; /* عرض 100% از والد */
|
||||
max-width: 600px; /* حداکثر عرض 600px */
|
||||
height: 100px; /* ارتفاع 100px */
|
||||
background-color: rgba(255, 255, 255, 0.1); /* مثال: زمینه نیمه شفاف سفید */
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* سایه برای دادن عمق */
|
||||
}
|
||||
|
||||
.audio-diary-admin-list-page #visualizer {
|
||||
background-color: #f9f9f9; /* پسزمینه ملایم */
|
||||
border-radius: 8px;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #f9f9f9; /* پسزمینه ملایم */
|
||||
border-radius: 8px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
/* تنظیمات کلی صفحه مدیریت */
|
||||
.audio-diary-admin-list-page {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #f4f4f9;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
color: #333;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #f4f4f9;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
|
||||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.audio-diary-admin-list-page h1 {
|
||||
color: #333;
|
||||
font-size: 24px;
|
||||
margin-bottom: 20px;
|
||||
color: #333;
|
||||
font-size: 24px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.audio-diary-admin-list-page button {
|
||||
background-color: #0073aa;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
font-size: 14px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
background-color: #0073aa;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
font-size: 14px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.audio-diary-admin-list-page button:hover {
|
||||
background-color: #005177;
|
||||
background-color: #005177;
|
||||
}
|
||||
|
||||
.audio-diary-admin-list-page table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.audio-diary-admin-list-page th,
|
||||
.audio-diary-admin-list-page td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
border: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.audio-diary-admin-list-page th {
|
||||
background-color: #0073aa;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
background-color: #0073aa;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.audio-diary-admin-list-page tr:nth-child(even) {
|
||||
background-color: #f9f9f9;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.audio-diary-admin-li st-page tr:hover {
|
||||
background-color: #f1f1f1;
|
||||
.audio-diary-admin-li st-page tr:hover {
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
.audio-diary-admin-list-page td audio {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* استایلهای اضافی برای ورودیهای چکباکس و دکمه حذف */
|
||||
.audio-diary-admin-list-page .select-audio {
|
||||
cursor: pointer;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.audio-diary-admin-list-page .delete-audio {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.audio-diary-admin-list-page .delete-audio:hover {
|
||||
background-color: #c82333;
|
||||
background-color: #c82333;
|
||||
}
|
||||
|
||||
/* استایلهای برای فوتر و هدر جدول */
|
||||
.audio-diary-admin-list-page thead {
|
||||
border-bottom: 2px solid #0073aa;
|
||||
border-bottom: 2px solid #0073aa;
|
||||
}
|
||||
|
||||
.audio-diary-admin-list-page tfoot {
|
||||
border-top: 2px solid #0073aa;
|
||||
background-color: #f2f2f2;
|
||||
border-top: 2px solid #0073aa;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
.audio-diary-admin-list-page {
|
||||
max-width: 900px;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.audio-diary-admin-list-page h1 {
|
||||
font-size: 26px;
|
||||
margin-bottom: 20px;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 20px;
|
||||
font-size: 14px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #0073aa;
|
||||
color: white;
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background-color: #005177;
|
||||
}
|
||||
.btn-danger {
|
||||
background-color: #e74c3c;
|
||||
color: white;
|
||||
}
|
||||
.btn-danger:hover {
|
||||
background-color: #c0392b;
|
||||
}
|
||||
.btn-secondary {
|
||||
background-color: #7f8c8d;
|
||||
color: white;
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
background-color: #6c757d;
|
||||
}
|
||||
.btn-small {
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.btn-upload {
|
||||
background-color: #27ae60;
|
||||
color: white;
|
||||
}
|
||||
.btn-upload:hover {
|
||||
background-color: #219653;
|
||||
}
|
||||
.btn-upload.uploaded {
|
||||
background-color: #95a5a6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.selected-count {
|
||||
font-size: 14px;
|
||||
color: #7f8c8d;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
border: 1px solid #e0e0e0;
|
||||
padding: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #34495e;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
tr:hover {
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
.action-cell {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
audio {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.select-audio {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,353 +1,427 @@
|
|||
jQuery(document).ready(function($) {
|
||||
let mediaRecorder;
|
||||
let audioChunks = [];
|
||||
let isRecording = false;
|
||||
let audioContext, analyser, dataArray, bufferLength, source;
|
||||
jQuery(document).ready(function ($) {
|
||||
let mediaRecorder;
|
||||
let audioChunks = [];
|
||||
let isRecording = false;
|
||||
let audioContext, analyser, dataArray, bufferLength, source;
|
||||
let isVisualizing = false;
|
||||
|
||||
function visualize(stream) {
|
||||
audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
||||
analyser = audioContext.createAnalyser();
|
||||
source = audioContext.createMediaStreamSource(stream);
|
||||
source.connect(analyser);
|
||||
analyser.fftSize = 2048;
|
||||
bufferLength = analyser.frequencyBinCount;
|
||||
dataArray = new Uint8Array(bufferLength);
|
||||
function visualize(stream) {
|
||||
audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
||||
analyser = audioContext.createAnalyser();
|
||||
source = audioContext.createMediaStreamSource(stream);
|
||||
source.connect(analyser);
|
||||
analyser.fftSize = 2048;
|
||||
bufferLength = analyser.frequencyBinCount;
|
||||
dataArray = new Uint8Array(bufferLength);
|
||||
|
||||
const canvas = document.getElementById('visualizer');
|
||||
const canvasCtx = canvas.getContext('2d');
|
||||
const canvas = document.getElementById("visualizer");
|
||||
const canvasCtx = canvas.getContext("2d");
|
||||
|
||||
function draw() {
|
||||
requestAnimationFrame(draw);
|
||||
analyser.getByteTimeDomainData(dataArray);
|
||||
function draw() {
|
||||
if (!isVisualizing) return;
|
||||
requestAnimationFrame(draw);
|
||||
analyser.getByteTimeDomainData(dataArray);
|
||||
|
||||
canvasCtx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
canvasCtx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const centerY = canvas.height / 2;
|
||||
canvasCtx.beginPath();
|
||||
canvasCtx.moveTo(0, centerY);
|
||||
canvasCtx.lineTo(canvas.width, centerY);
|
||||
canvasCtx.strokeStyle = 'rgba(0, 0, 0, 0.2)';
|
||||
canvasCtx.lineWidth = 1;
|
||||
canvasCtx.stroke();
|
||||
const centerY = canvas.height / 2;
|
||||
canvasCtx.beginPath();
|
||||
canvasCtx.moveTo(0, centerY);
|
||||
canvasCtx.lineTo(canvas.width, centerY);
|
||||
canvasCtx.strokeStyle = "rgba(0, 0, 0, 0.2)";
|
||||
canvasCtx.lineWidth = 1;
|
||||
canvasCtx.stroke();
|
||||
|
||||
canvasCtx.lineWidth = 2;
|
||||
canvasCtx.strokeStyle = 'rgb(0, 0, 0)';
|
||||
canvasCtx.lineWidth = 2;
|
||||
canvasCtx.strokeStyle = "rgb(0, 0, 0)";
|
||||
|
||||
canvasCtx.beginPath();
|
||||
let sliceWidth = canvas.width * 1.0 / bufferLength;
|
||||
let x = 0;
|
||||
canvasCtx.beginPath();
|
||||
let sliceWidth = (canvas.width * 1.0) / bufferLength;
|
||||
let x = 0;
|
||||
|
||||
for (let i = 0; i < bufferLength; i++) {
|
||||
let v = dataArray[i] / 128.0;
|
||||
let y = v * canvas.height / 2;
|
||||
for (let i = 0; i < bufferLength; i++) {
|
||||
let v = dataArray[i] / 128.0;
|
||||
let y = (v * canvas.height) / 2;
|
||||
|
||||
if (i === 0) {
|
||||
canvasCtx.moveTo(x, y);
|
||||
} else {
|
||||
canvasCtx.lineTo(x, y);
|
||||
}
|
||||
|
||||
x += sliceWidth;
|
||||
}
|
||||
|
||||
canvasCtx.lineTo(canvas.width, canvas.height / 2);
|
||||
canvasCtx.stroke();
|
||||
if (i === 0) {
|
||||
canvasCtx.moveTo(x, y);
|
||||
} else {
|
||||
canvasCtx.lineTo(x, y);
|
||||
}
|
||||
|
||||
draw();
|
||||
x += sliceWidth;
|
||||
}
|
||||
|
||||
canvasCtx.lineTo(canvas.width, canvas.height / 2);
|
||||
canvasCtx.stroke();
|
||||
}
|
||||
|
||||
|
||||
$('#download-zip').on('click', function() {
|
||||
var selectedFiles = [];
|
||||
$('.select-audio:checked').each(function() {
|
||||
selectedFiles.push($(this).val());
|
||||
});
|
||||
isVisualizing = true;
|
||||
draw();
|
||||
}
|
||||
|
||||
if (selectedFiles.length > 0) {
|
||||
var form = document.createElement('form');
|
||||
form.method = 'POST';
|
||||
form.action = '';
|
||||
function showToast(message, type) {
|
||||
$.toast({
|
||||
text: message,
|
||||
heading: "Note",
|
||||
icon: type,
|
||||
showHideTransition: "fade",
|
||||
allowToastClose: true,
|
||||
hideAfter: 3000,
|
||||
stack: 3,
|
||||
position: "bottom-center",
|
||||
textAlign: "left",
|
||||
loader: true,
|
||||
loaderBg: type === "success" ? "#9EC600" : "#FF0000",
|
||||
});
|
||||
}
|
||||
|
||||
selectedFiles.forEach(function(file) {
|
||||
var input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'selected_files[]';
|
||||
input.value = file;
|
||||
form.appendChild(input);
|
||||
});
|
||||
$(".download-single").on("click", function () {
|
||||
var $button = $(this);
|
||||
var fileUrl = $button.data("url");
|
||||
var fileName = $button.data("name");
|
||||
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
} else {
|
||||
$.toast({
|
||||
text: "Please select at least one audio file to download.",
|
||||
heading: 'Note',
|
||||
icon: 'error',
|
||||
showHideTransition: 'fade',
|
||||
allowToastClose: true,
|
||||
hideAfter: 3000,
|
||||
stack: 3,
|
||||
position: 'bottom-center',
|
||||
textAlign: 'left',
|
||||
loader: true,
|
||||
loaderBg: '#FF0000',
|
||||
});
|
||||
}
|
||||
var downloadLink = document.createElement("a");
|
||||
downloadLink.href = fileUrl;
|
||||
downloadLink.download = fileName;
|
||||
document.body.appendChild(downloadLink);
|
||||
downloadLink.click();
|
||||
document.body.removeChild(downloadLink);
|
||||
});
|
||||
|
||||
$("#download-zip").on("click", function () {
|
||||
var selectedFiles = [];
|
||||
$(".select-audio:checked").each(function () {
|
||||
selectedFiles.push($(this).val());
|
||||
});
|
||||
|
||||
if (selectedFiles.length > 0) {
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: "POST",
|
||||
data: {
|
||||
action: "download_zip",
|
||||
files: selectedFiles,
|
||||
},
|
||||
success: function (response) {
|
||||
if (response.success) {
|
||||
showToast("Zip file created successfully", "success");
|
||||
var downloadLink = document.createElement("a");
|
||||
downloadLink.href = response.data.zip_url;
|
||||
downloadLink.download = response.data.zip_url.split("/").pop();
|
||||
document.body.appendChild(downloadLink);
|
||||
downloadLink.click();
|
||||
document.body.removeChild(downloadLink);
|
||||
$(".select-audio").prop("checked", false);
|
||||
} else {
|
||||
showToast("Failed to create zip file: " + response.data, "error");
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
showToast("AJAX Error: " + textStatus + ": " + errorThrown, "error");
|
||||
},
|
||||
});
|
||||
} else {
|
||||
showToast("Please select at least one audio file to download.", "error");
|
||||
}
|
||||
});
|
||||
|
||||
$("#recording-button").on("click", function () {
|
||||
if (!isRecording) {
|
||||
navigator.mediaDevices
|
||||
.getUserMedia({ audio: true })
|
||||
.then((stream) => {
|
||||
mediaRecorder = new MediaRecorder(stream);
|
||||
audioChunks = [];
|
||||
mediaRecorder.start();
|
||||
visualize(stream);
|
||||
|
||||
$('#recording-button').on('click', function() {
|
||||
if (!isRecording) {
|
||||
navigator.mediaDevices.getUserMedia({ audio: true })
|
||||
.then(stream => {
|
||||
mediaRecorder = new MediaRecorder(stream);
|
||||
mediaRecorder.start();
|
||||
visualize(stream);
|
||||
|
||||
mediaRecorder.ondataavailable = function(event) {
|
||||
audioChunks.push(event.data);
|
||||
};
|
||||
mediaRecorder.ondataavailable = function (event) {
|
||||
audioChunks.push(event.data);
|
||||
};
|
||||
|
||||
mediaRecorder.onstop = function() {
|
||||
const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
|
||||
audioChunks = [];
|
||||
const audioUrl = URL.createObjectURL(audioBlob);
|
||||
$('#audio-player').attr('src', audioUrl).addClass('show');
|
||||
mediaRecorder.onstop = function () {
|
||||
stream.getTracks().forEach((track) => track.stop());
|
||||
const audioBlob = new Blob(audioChunks, { type: "audio/wav" });
|
||||
audioChunks = [];
|
||||
const audioUrl = URL.createObjectURL(audioBlob);
|
||||
$("#audio-player").attr("src", audioUrl).addClass("show");
|
||||
|
||||
let formData = new FormData();
|
||||
formData.append('audio_data', audioBlob, 'audio.wav');
|
||||
formData.append('action', 'save_audio');
|
||||
let formData = new FormData();
|
||||
formData.append("audio_data", audioBlob, "audio.wav");
|
||||
formData.append("action", "save_audio");
|
||||
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
$.toast({
|
||||
text: "Audio saved successfully",
|
||||
heading: 'Note',
|
||||
icon: 'success',
|
||||
showHideTransition: 'fade',
|
||||
allowToastClose: true,
|
||||
hideAfter: 3000,
|
||||
stack: 3,
|
||||
position: 'bottom-center',
|
||||
textAlign: 'left',
|
||||
loader: true,
|
||||
loaderBg: '#9EC600',
|
||||
});
|
||||
} else {
|
||||
$.toast({
|
||||
text: "Failed to save audio",
|
||||
heading: 'Note',
|
||||
icon: 'error',
|
||||
showHideTransition: 'fade',
|
||||
allowToastClose: true,
|
||||
hideAfter: 3000,
|
||||
stack: 3,
|
||||
position: 'bottom-center',
|
||||
textAlign: 'left',
|
||||
loader: true,
|
||||
loaderBg: '#9EC600',
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$('#visualizer').show();
|
||||
isRecording = true;
|
||||
$('#recording-button').css('background-color', 'green');
|
||||
});
|
||||
} else {
|
||||
mediaRecorder.stop();
|
||||
$('#visualizer').hide();
|
||||
isRecording = false;
|
||||
$('#recording-button').css('background-color', 'red');
|
||||
}
|
||||
});
|
||||
|
||||
$('#download-selected').on('click', function() {
|
||||
let selectedFiles = [];
|
||||
$('.select-audio:checked').each(function() {
|
||||
selectedFiles.push($(this).val());
|
||||
});
|
||||
|
||||
if (selectedFiles.length > 0) {
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'download_zip',
|
||||
files: selectedFiles
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
$.toast({
|
||||
text: "Zip file created successfully",
|
||||
heading: 'Note',
|
||||
icon: 'success',
|
||||
showHideTransition: 'fade',
|
||||
allowToastClose: true,
|
||||
hideAfter: 3000,
|
||||
stack: 3,
|
||||
position: 'bottom-center',
|
||||
textAlign: 'left',
|
||||
loader: true,
|
||||
loaderBg: '#9EC600',
|
||||
});
|
||||
|
||||
// ایجاد لینک دانلود
|
||||
let downloadLink = document.createElement('a');
|
||||
downloadLink.href = response.data.zip_url;
|
||||
downloadLink.download = response.data.zip_url.split('/').pop();
|
||||
document.body.appendChild(downloadLink);
|
||||
downloadLink.click();
|
||||
document.body.removeChild(downloadLink);
|
||||
|
||||
// برداشتن انتخاب فایلهای صوتی
|
||||
$('.select-audio').prop('checked', false);
|
||||
} else {
|
||||
$.toast({
|
||||
text: "Failed to create zip file: " + response.data,
|
||||
heading: 'Error',
|
||||
icon: 'error',
|
||||
showHideTransition: 'fade',
|
||||
allowToastClose: true,
|
||||
hideAfter: 3000,
|
||||
stack: 3,
|
||||
position: 'bottom-center',
|
||||
textAlign: 'left',
|
||||
loader: true,
|
||||
loaderBg: '#FF0000',
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
console.log('AJAX Error: ' + textStatus + ': ' + errorThrown);
|
||||
$.toast({
|
||||
text: "AJAX Error: " + textStatus + ": " + errorThrown,
|
||||
heading: 'Error',
|
||||
icon: 'error',
|
||||
showHideTransition: 'fade',
|
||||
allowToastClose: true,
|
||||
hideAfter: 3000,
|
||||
stack: 3,
|
||||
position: 'bottom-center',
|
||||
textAlign: 'left',
|
||||
loader: true,
|
||||
loaderBg: '#FF0000',
|
||||
});
|
||||
url: ajaxurl,
|
||||
type: "POST",
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function (response) {
|
||||
if (response.success) {
|
||||
showToast("Audio saved successfully", "success");
|
||||
} else {
|
||||
showToast("Failed to save audio", "error");
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$("#visualizer").show();
|
||||
isRecording = true;
|
||||
$("#recording-button").css("background-color", "green");
|
||||
})
|
||||
.catch((error) => {
|
||||
showToast("Unable to access microphone: " + error.message, "error");
|
||||
});
|
||||
} else {
|
||||
mediaRecorder.stop();
|
||||
$("#visualizer").hide();
|
||||
isVisualizing = false;
|
||||
audioContext.close();
|
||||
isRecording = false;
|
||||
$("#recording-button").css("background-color", "red");
|
||||
}
|
||||
});
|
||||
|
||||
$("#download-selected").on("click", function () {
|
||||
let selectedFiles = [];
|
||||
$(".select-audio:checked").each(function () {
|
||||
selectedFiles.push($(this).val());
|
||||
});
|
||||
|
||||
$('#select-all').on('click', function() {
|
||||
let isSelectAll = $(this).data('select-all');
|
||||
|
||||
if (isSelectAll) {
|
||||
$('.select-audio').prop('checked', true);
|
||||
$(this).text('Unselect All');
|
||||
} else {
|
||||
$('.select-audio').prop('checked', false);
|
||||
$(this).text('Select All');
|
||||
}
|
||||
|
||||
// تغییر حالت دکمه
|
||||
$(this).data('select-all', !isSelectAll);
|
||||
if (selectedFiles.length > 0) {
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: "POST",
|
||||
data: {
|
||||
action: "download_zip",
|
||||
files: selectedFiles,
|
||||
},
|
||||
success: function (response) {
|
||||
if (response.success) {
|
||||
showToast("Zip file created successfully", "success");
|
||||
let downloadLink = document.createElement("a");
|
||||
downloadLink.href = response.data.zip_url;
|
||||
downloadLink.download = response.data.zip_url.split("/").pop();
|
||||
document.body.appendChild(downloadLink);
|
||||
downloadLink.click();
|
||||
document.body.removeChild(downloadLink);
|
||||
$(".select-audio").prop("checked", false);
|
||||
} else {
|
||||
showToast("Failed to create zip file: " + response.data, "error");
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
showToast("AJAX Error: " + textStatus + ": " + errorThrown, "error");
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$("#select-all").on("click", function () {
|
||||
let isSelectAll = $(this).data("select-all");
|
||||
if (isSelectAll) {
|
||||
$(".select-audio").prop("checked", true);
|
||||
$(this).text("Unselect All");
|
||||
} else {
|
||||
$(".select-audio").prop("checked", false);
|
||||
$(this).text("Select All");
|
||||
}
|
||||
$(this).data("select-all", !isSelectAll);
|
||||
});
|
||||
|
||||
// فقط یه رویداد برای #delete-selected
|
||||
$("#delete-selected").on("click", function () {
|
||||
const selectedFiles = [];
|
||||
$(".select-audio:checked").each(function () {
|
||||
selectedFiles.push($(this).val());
|
||||
});
|
||||
|
||||
|
||||
// حذف فایلهای انتخابشده
|
||||
$('#delete-selected').on('click', function() {
|
||||
let selectedFiles = [];
|
||||
$('.select-audio:checked').each(function() {
|
||||
selectedFiles.push($(this).val());
|
||||
});
|
||||
|
||||
if (selectedFiles.length > 0 && confirm("Are you sure you want to delete selected audio files?")) {
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'delete_selected_audios',
|
||||
files: selectedFiles
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
$.toast({
|
||||
text: "Selected audio files deleted successfully",
|
||||
heading: 'Note',
|
||||
icon: 'success',
|
||||
showHideTransition: 'fade',
|
||||
allowToastClose: true,
|
||||
hideAfter: 3000,
|
||||
stack: 3,
|
||||
position: 'bottom-center',
|
||||
textAlign: 'left',
|
||||
loader: true,
|
||||
loaderBg: '#9EC600',
|
||||
});
|
||||
|
||||
// پس از حذف موفق فایلها، لیست را بهروزرسانی کنید
|
||||
selectedFiles.forEach(function(fileName) {
|
||||
$('.delete-audio[data-file="' + fileName + '"]').closest('tr').fadeOut(400, function() {
|
||||
$(this).remove();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$.toast({
|
||||
text: "Failed to delete selected audio files: " + response.data,
|
||||
heading: 'Error',
|
||||
icon: 'error',
|
||||
showHideTransition: 'fade',
|
||||
allowToastClose: true,
|
||||
hideAfter: 3000,
|
||||
stack: 3,
|
||||
position: 'bottom-center',
|
||||
textAlign: 'left',
|
||||
loader: true,
|
||||
loaderBg: '#FF0000',
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
console.log('AJAX Error: ' + textStatus + ': ' + errorThrown);
|
||||
$.toast({
|
||||
text: "AJAX Error: " + textStatus + ": " + errorThrown,
|
||||
heading: 'Error',
|
||||
icon: 'error',
|
||||
showHideTransition: 'fade',
|
||||
allowToastClose: true,
|
||||
hideAfter: 3000,
|
||||
stack: 3,
|
||||
position: 'bottom-center',
|
||||
textAlign: 'left',
|
||||
loader: true,
|
||||
loaderBg: '#FF0000',
|
||||
});
|
||||
}
|
||||
|
||||
if (selectedFiles.length === 0) {
|
||||
showToast("Please select at least one audio file to delete.", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmDialog = confirm(
|
||||
"Are you sure you want to delete " +
|
||||
selectedFiles.length +
|
||||
" selected file(s)?\nPress OK to delete only locally, or Cancel and choose below."
|
||||
);
|
||||
if (!confirmDialog) {
|
||||
const deleteFromDrive = confirm(
|
||||
"Also delete these files from Google Drive?"
|
||||
);
|
||||
deleteFiles(selectedFiles, deleteFromDrive);
|
||||
} else {
|
||||
deleteFiles(selectedFiles, false);
|
||||
}
|
||||
});
|
||||
|
||||
function deleteFiles(files, deleteFromDrive) {
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: "POST",
|
||||
data: {
|
||||
action: "audio_diary_delete_selected_audios",
|
||||
files: files,
|
||||
delete_from_drive: deleteFromDrive,
|
||||
},
|
||||
success: function (response) {
|
||||
if (response.success) {
|
||||
showToast(
|
||||
"Deleted " +
|
||||
(response.deleted_local || 0) +
|
||||
" local file(s) and " +
|
||||
(response.deleted_drive || 0) +
|
||||
" Google Drive file(s) successfully!",
|
||||
"success"
|
||||
);
|
||||
files.forEach(function (fileName) {
|
||||
const $row = $('tr[data-file="' + fileName + '"]');
|
||||
$row
|
||||
.find(".upload-to-drive")
|
||||
.text("Upload to Drive")
|
||||
.removeClass("uploaded")
|
||||
.prop("disabled", false);
|
||||
$row.fadeOut(400, function () {
|
||||
$(this).remove();
|
||||
});
|
||||
});
|
||||
if (response.data && response.data.drive_errors) {
|
||||
showToast(response.data.drive_errors, "warning");
|
||||
}
|
||||
} else {
|
||||
$.toast({
|
||||
text: "Please select at least one audio file to delete.",
|
||||
heading: 'Error',
|
||||
icon: 'error',
|
||||
showHideTransition: 'fade',
|
||||
allowToastClose: true,
|
||||
hideAfter: 3000,
|
||||
stack: 3,
|
||||
position: 'bottom-center',
|
||||
textAlign: 'left',
|
||||
loader: true,
|
||||
loaderBg: '#FF0000',
|
||||
});
|
||||
showToast(
|
||||
"Failed to delete files: " + (response.data || "Unknown error"),
|
||||
"error"
|
||||
);
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
showToast("AJAX Error: " + textStatus + " - " + errorThrown, "error");
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(".upload-to-drive").on("click", function () {
|
||||
const $button = $(this);
|
||||
const fileName = $button.data("name");
|
||||
|
||||
if ($button.hasClass("uploaded")) {
|
||||
showToast("This file is already uploaded to Google Drive.", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
$button.text("Uploading...").prop("disabled", true);
|
||||
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: "POST",
|
||||
data: {
|
||||
action: "upload_to_google_drive",
|
||||
file: fileName,
|
||||
},
|
||||
success: function (response) {
|
||||
if (response.success) {
|
||||
showToast("File uploaded to Google Drive successfully!", "success");
|
||||
$button.text("Uploaded").addClass("uploaded").prop("disabled", true);
|
||||
} else {
|
||||
if (response.data === "File already exists in Google Drive.") {
|
||||
showToast("This file already exists in Google Drive.", "error");
|
||||
$button
|
||||
.text("Uploaded")
|
||||
.addClass("uploaded")
|
||||
.prop("disabled", true);
|
||||
} else {
|
||||
showToast("Failed to upload: " + response.data, "error");
|
||||
$button.text("Upload to Drive").prop("disabled", false);
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
showToast("Upload Error: " + textStatus, "error");
|
||||
$button.text("Upload to Drive").prop("disabled", false);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
$("button#audioduration").on("click", function () {
|
||||
var $button = $(this);
|
||||
if ($button.data("loaded")) return;
|
||||
var audioUrl = $button.closest("td").find(".audio-duration").data("url");
|
||||
|
||||
if (!audioUrl) {
|
||||
$button.text("خطا");
|
||||
return;
|
||||
}
|
||||
|
||||
$button.text("در حال بارگذاری...");
|
||||
var audio = new Audio(audioUrl);
|
||||
|
||||
audio.addEventListener("canplaythrough", function () {
|
||||
var duration = audio.duration;
|
||||
|
||||
if (isNaN(duration) || duration <= 0) {
|
||||
$button.text("خطا");
|
||||
return;
|
||||
}
|
||||
|
||||
var minutes = Math.floor(duration / 60);
|
||||
var seconds = Math.floor(duration % 60);
|
||||
var formattedDuration =
|
||||
minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
|
||||
|
||||
$button.text(formattedDuration);
|
||||
$button.data("loaded", true);
|
||||
});
|
||||
|
||||
audio.addEventListener("error", function () {
|
||||
$button.text("خطا");
|
||||
});
|
||||
|
||||
audio.load();
|
||||
});
|
||||
|
||||
$("button.audioduration").on("click", function () {
|
||||
var $button = $(this);
|
||||
if ($button.data("loaded")) return;
|
||||
|
||||
var audioUrl = $button.closest("td").find(".audio-duration").data("url");
|
||||
if (!audioUrl) {
|
||||
$button.text("خطا");
|
||||
return;
|
||||
}
|
||||
|
||||
$button.text("در حال بارگذاری...");
|
||||
var audio = new Audio(audioUrl);
|
||||
|
||||
audio.addEventListener("canplaythrough", function () {
|
||||
var duration = audio.duration;
|
||||
|
||||
if (isNaN(duration) || duration <= 0) {
|
||||
$button.text("خطا");
|
||||
return;
|
||||
}
|
||||
|
||||
var minutes = Math.floor(duration / 60);
|
||||
var seconds = Math.floor(duration % 60);
|
||||
var formattedDuration =
|
||||
minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
|
||||
|
||||
$button.text(formattedDuration);
|
||||
$button.data("loaded", true);
|
||||
});
|
||||
|
||||
audio.addEventListener("error", function () {
|
||||
$button.text("خطا");
|
||||
});
|
||||
|
||||
audio.load();
|
||||
});
|
||||
|
||||
$(".select-audio").on("change", function () {
|
||||
let count = $(".select-audio:checked").length;
|
||||
$("#selected-count").text(`Selected: ${count}`);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
Plugin Name: Audio diary
|
||||
Description: پلاگین دفترچه خاطرات.
|
||||
Author: haakel
|
||||
Version: 2.0.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
|
|
|
|||
|
|
@ -1,46 +1,191 @@
|
|||
<?php
|
||||
<?php
|
||||
|
||||
class Audio_Diary_Admin_Page {
|
||||
|
||||
/**
|
||||
* Instance
|
||||
*
|
||||
* @access private
|
||||
* @var object Class object.
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private static $instance;
|
||||
private static $instance;
|
||||
|
||||
/**
|
||||
* Initiator
|
||||
*
|
||||
* @return object Initialized object of class.
|
||||
* @since 1.0.0
|
||||
*/
|
||||
|
||||
public static function get_instance() {
|
||||
if ( ! isset( self::$instance ) ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
public static function get_instance() {
|
||||
if (!isset(self::$instance)) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
add_action('admin_menu', array($this, 'add_menu_item'));
|
||||
add_action('admin_enqueue_scripts', array($this, 'enqueue_scripts'));
|
||||
add_action('wp_ajax_save_audio', array($this, 'save_audio'));
|
||||
add_action('wp_ajax_delete_audio', array($this, 'delete_audio'));
|
||||
add_action('wp_ajax_delete_selected_audios', array($this, 'delete_selected_audios'));
|
||||
add_action('wp_ajax_download_zip', array($this,'handle_download_zip'));
|
||||
add_action('wp_ajax_delete_selected_audios', array($this, 'delete_selected_audios')); // نگه داشتم برای سازگاری
|
||||
add_action('wp_ajax_download_zip', array($this, 'handle_download_zip'));
|
||||
add_action('wp_ajax_upload_to_google_drive', array($this, 'audio_diary_upload_to_google_drive'));
|
||||
add_action('wp_ajax_audio_diary_delete_selected_audios', array($this, 'audio_diary_delete_selected_audios'));
|
||||
add_action('wp_ajax_audio_diary_test_connection', array($this, 'test_connection'));
|
||||
$this->create_audio_folder();
|
||||
}
|
||||
|
||||
public function test_connection() {
|
||||
check_ajax_referer('audio_diary_test_connection_nonce', 'nonce');
|
||||
if (!isset($_POST['folder_id']) || empty($_POST['folder_id'])) {
|
||||
wp_send_json_error(__('Invalid Folder ID.', 'audio-diary'));
|
||||
}
|
||||
|
||||
$folder_id = sanitize_text_field($_POST['folder_id']);
|
||||
require_once plugin_dir_path(__FILE__) . '../vendor/autoload.php';
|
||||
$client = new Google_Client();
|
||||
$client->setAuthConfig(plugin_dir_path(__FILE__) . '../config/service-account.json');
|
||||
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
|
||||
$service = new Google_Service_Drive($client);
|
||||
|
||||
try {
|
||||
$folder = $service->files->get($folder_id, ['fields' => 'id,name']);
|
||||
error_log("Test connection successful for folder ID: $folder_id, Name: " . $folder->getName());
|
||||
wp_send_json_success();
|
||||
} catch (Google_Service_Exception $e) {
|
||||
error_log("Test connection failed for $folder_id: " . $e->getMessage());
|
||||
if ($e->getCode() == 404) {
|
||||
wp_send_json_error(__('Folder not found. Check the Folder ID.', 'audio-diary'));
|
||||
} elseif ($e->getCode() == 403) {
|
||||
wp_send_json_error(__('Permission denied. Ensure the Service Account has access to this folder.', 'audio-diary'));
|
||||
} else {
|
||||
wp_send_json_error(__('Failed to connect: ' . $e->getMessage(), 'audio-diary'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function audio_diary_upload_to_google_drive() {
|
||||
$file_name = isset($_POST['file']) ? sanitize_file_name($_POST['file']) : '';
|
||||
if (!$file_name) {
|
||||
error_log('Upload Error: No file specified.');
|
||||
wp_send_json_error('No file specified.');
|
||||
}
|
||||
|
||||
$uploads = wp_upload_dir();
|
||||
$file_path = $uploads['basedir'] . '/audio-diary/' . $file_name;
|
||||
|
||||
if (!file_exists($file_path)) {
|
||||
error_log("Upload Error: File not found on server - $file_path");
|
||||
wp_send_json_error('File not found on server.');
|
||||
}
|
||||
|
||||
require_once plugin_dir_path(__FILE__) . '../vendor/autoload.php';
|
||||
$client = new Google_Client();
|
||||
$client->setAuthConfig(plugin_dir_path(__FILE__) . '../config/service-account.json');
|
||||
$client->addScope(Google_Service_Drive::DRIVE); // تغییر به DRIVE برای دسترسی کامل
|
||||
$service = new Google_Service_Drive($client);
|
||||
|
||||
$target_folder_id = get_option('audio_diary_google_drive_folder_id', '1sBE78fuxRlcWouLs0mw12zLqTbWJg9jB');
|
||||
$drive_file_id = get_option('google_drive_' . $file_name);
|
||||
error_log("Checking file: $file_name, Drive ID: " . ($drive_file_id ? $drive_file_id : 'None'));
|
||||
|
||||
if ($drive_file_id) {
|
||||
try {
|
||||
$file = $service->files->get($drive_file_id, ['fields' => 'id,name,parents,trashed']);
|
||||
$parents = $file->getParents();
|
||||
$trashed = $file->getTrashed();
|
||||
error_log("File $file_name exists in Google Drive with ID: $drive_file_id, Name: " . $file->getName() . ", Parents: " . implode(',', $parents) . ", Trashed: " . ($trashed ? 'Yes' : 'No'));
|
||||
|
||||
if (in_array($target_folder_id, $parents) && !$trashed) {
|
||||
wp_send_json_error('File already exists in the target Google Drive folder.');
|
||||
} else {
|
||||
error_log("File $file_name is not in target folder or is trashed, proceeding to upload.");
|
||||
delete_option('google_drive_' . $file_name);
|
||||
}
|
||||
} catch (Google_Service_Exception $e) {
|
||||
error_log("Google Drive check failed for $file_name: " . $e->getMessage() . " (Code: " . $e->getCode() . ")");
|
||||
if ($e->getCode() == 404) {
|
||||
delete_option('google_drive_' . $file_name);
|
||||
error_log("Deleted option for $file_name as it was not found in Google Drive.");
|
||||
} else {
|
||||
wp_send_json_error('Error checking file in Google Drive: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error_log("No Drive ID found for $file_name, proceeding to upload.");
|
||||
}
|
||||
|
||||
error_log("Uploading $file_name to Google Drive...");
|
||||
$file = new Google_Service_Drive_DriveFile();
|
||||
$file->setName($file_name);
|
||||
$file->setParents([$target_folder_id]);
|
||||
|
||||
$result = $service->files->create($file, [
|
||||
'data' => file_get_contents($file_path),
|
||||
'mimeType' => 'audio/wav',
|
||||
'uploadType' => 'multipart'
|
||||
]);
|
||||
|
||||
if ($result) {
|
||||
update_option('google_drive_' . $file_name, $result->id);
|
||||
error_log("Upload successful for $file_name, new ID: " . $result->id);
|
||||
wp_send_json_success(['file_id' => $result->id]);
|
||||
} else {
|
||||
error_log("Upload failed for $file_name");
|
||||
wp_send_json_error('Upload failed.');
|
||||
}
|
||||
}
|
||||
|
||||
function audio_diary_delete_selected_audios() {
|
||||
$files = isset($_POST['files']) ? (array)$_POST['files'] : [];
|
||||
$delete_from_drive = isset($_POST['delete_from_drive']) && $_POST['delete_from_drive'] === 'true';
|
||||
|
||||
if (empty($files)) {
|
||||
wp_send_json_error('No files selected.');
|
||||
}
|
||||
|
||||
$uploads = wp_upload_dir();
|
||||
$deleted_local = 0;
|
||||
$deleted_drive = 0;
|
||||
$drive_errors = [];
|
||||
|
||||
if ($delete_from_drive) {
|
||||
require_once plugin_dir_path(__FILE__) . '../vendor/autoload.php';
|
||||
$client = new Google_Client();
|
||||
$client->setAuthConfig(plugin_dir_path(__FILE__) . '../config/service-account.json');
|
||||
$client->addScope(Google_Service_Drive::DRIVE);
|
||||
$service = new Google_Service_Drive($client);
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
$file_path = $uploads['basedir'] . '/audio-diary/' . sanitize_file_name($file);
|
||||
$drive_file_id = get_option('google_drive_' . $file);
|
||||
|
||||
if ($delete_from_drive && $drive_file_id) {
|
||||
try {
|
||||
$service->files->delete($drive_file_id);
|
||||
delete_option('google_drive_' . $file);
|
||||
$deleted_drive++;
|
||||
error_log("Successfully deleted file $drive_file_id from Google Drive for $file.");
|
||||
} catch (Google_Service_Exception $e) {
|
||||
$drive_errors[] = "Failed to delete $file from Google Drive: " . $e->getMessage() . " (Code: " . $e->getCode() . ")";
|
||||
error_log($drive_errors[count($drive_errors) - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (file_exists($file_path) && unlink($file_path)) {
|
||||
$deleted_local++;
|
||||
error_log("Successfully deleted local file: $file_path");
|
||||
} else {
|
||||
error_log("No local file to delete or failed: $file_path");
|
||||
}
|
||||
}
|
||||
|
||||
if ($deleted_local > 0 || $deleted_drive > 0) {
|
||||
$response = ['success' => true, 'deleted_local' => $deleted_local, 'deleted_drive' => $deleted_drive];
|
||||
if (!empty($drive_errors)) {
|
||||
$response['data'] = ['drive_errors' => implode("; ", $drive_errors)];
|
||||
}
|
||||
wp_send_json($response);
|
||||
} else {
|
||||
wp_send_json_error('Failed to delete any files.');
|
||||
}
|
||||
}
|
||||
|
||||
function delete_old_zip_files() {
|
||||
$uploads = wp_upload_dir();
|
||||
$files = glob($uploads['basedir'] . '/audio-diary-selected-*.zip');
|
||||
$time_limit = 3600; // 1 hour in seconds
|
||||
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (filemtime($file) < (time() - $time_limit)) {
|
||||
unlink($file);
|
||||
|
|
@ -49,57 +194,47 @@ class Audio_Diary_Admin_Page {
|
|||
}
|
||||
|
||||
function handle_download_zip() {
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_send_json_error(['message' => 'Unauthorized']);
|
||||
return;
|
||||
$files = isset($_POST['files']) ? (array)$_POST['files'] : [];
|
||||
if (empty($files)) {
|
||||
wp_send_json_error('No files selected.');
|
||||
}
|
||||
|
||||
if (!isset($_POST['files']) || !is_array($_POST['files'])) {
|
||||
wp_send_json_error(['message' => 'Invalid request']);
|
||||
return;
|
||||
}
|
||||
|
||||
$selected_files = $_POST['files'];
|
||||
|
||||
$uploads = wp_upload_dir();
|
||||
$zip_name = 'audio-diary-' . time() . '.zip';
|
||||
$zip_path = $uploads['basedir'] . '/' . $zip_name;
|
||||
$zip = new ZipArchive();
|
||||
$zip_filename = 'audio-diary-selected-' . time() . '.zip';
|
||||
$zip_filepath = $uploads['basedir'] . '/' . $zip_filename;
|
||||
|
||||
if ($zip->open($zip_filepath, ZipArchive::CREATE) !== TRUE) {
|
||||
wp_send_json_error(['message' => 'Cannot create zip file']);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($selected_files as $file) {
|
||||
$file_path = $uploads['basedir'] . '/audio-diary/' . $file;
|
||||
if (file_exists($file_path)) {
|
||||
$zip->addFile($file_path, $file);
|
||||
|
||||
if ($zip->open($zip_path, ZipArchive::CREATE) === TRUE) {
|
||||
foreach ($files as $file) {
|
||||
$file_path = $uploads['basedir'] . '/audio-diary/' . sanitize_file_name($file);
|
||||
if (file_exists($file_path)) {
|
||||
$zip->addFile($file_path, $file);
|
||||
}
|
||||
}
|
||||
$zip->close();
|
||||
|
||||
$zip_url = $uploads['baseurl'] . '/' . $zip_name;
|
||||
wp_send_json_success(['zip_url' => $zip_url]);
|
||||
} else {
|
||||
wp_send_json_error('Failed to create ZIP file.');
|
||||
}
|
||||
|
||||
$zip->close();
|
||||
|
||||
$zip_url = $uploads['baseurl'] . '/' . $zip_filename;
|
||||
|
||||
wp_send_json_success(['zip_url' => $zip_url]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function delete_audio() {
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_send_json_error('Unauthorized');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (empty($_POST['file_name'])) {
|
||||
wp_send_json_error('No file specified');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$file_name = sanitize_file_name($_POST['file_name']);
|
||||
$uploads = wp_upload_dir();
|
||||
$file_path = $uploads['basedir'] . '/audio-diary/' . $file_name;
|
||||
|
||||
|
||||
if (file_exists($file_path) && unlink($file_path)) {
|
||||
wp_send_json_success('File deleted');
|
||||
} else {
|
||||
|
|
@ -107,70 +242,39 @@ class Audio_Diary_Admin_Page {
|
|||
wp_send_json_error($error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function delete_selected_audios() {
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_send_json_error('Unauthorized');
|
||||
return;
|
||||
$files = isset($_POST['files']) ? (array)$_POST['files'] : [];
|
||||
if (empty($files)) {
|
||||
wp_send_json_error('No files selected.');
|
||||
}
|
||||
|
||||
if (empty($_POST['files']) || !is_array($_POST['files'])) {
|
||||
wp_send_json_error('No files specified');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$uploads = wp_upload_dir();
|
||||
$base_path = wp_normalize_path($uploads['basedir'] . '/audio-diary/');
|
||||
$errors = [];
|
||||
|
||||
// Print existing files in the directory
|
||||
$existing_files = glob($base_path . '*');
|
||||
error_log("Existing files in audio-diary directory:");
|
||||
foreach ($existing_files as $file) {
|
||||
error_log(basename($file));
|
||||
}
|
||||
|
||||
foreach ($_POST['files'] as $file_name) {
|
||||
$file_name = sanitize_file_name($file_name);
|
||||
|
||||
// اصلاح نام فایل، جایگزین کردن فاصله با خط تیره
|
||||
$file_name = str_replace(' ', '-', $file_name);
|
||||
|
||||
$file_path = wp_normalize_path($base_path . $file_name);
|
||||
|
||||
error_log("Trying to delete: " . $file_path);
|
||||
|
||||
if (file_exists($file_path)) {
|
||||
if (!unlink($file_path)) {
|
||||
error_log("Failed to delete: " . $file_path);
|
||||
$errors[] = $file_name;
|
||||
} else {
|
||||
error_log("Deleted: " . $file_path);
|
||||
}
|
||||
} else {
|
||||
error_log("File not found: " . $file_path);
|
||||
$errors[] = $file_name;
|
||||
$deleted = 0;
|
||||
|
||||
foreach ($files as $file) {
|
||||
$file_path = $uploads['basedir'] . '/audio-diary/' . sanitize_file_name($file);
|
||||
if (file_exists($file_path) && unlink($file_path)) {
|
||||
$deleted++;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($errors)) {
|
||||
wp_send_json_success('All files deleted successfully.');
|
||||
|
||||
if ($deleted > 0) {
|
||||
wp_send_json_success('Deleted ' . $deleted . ' files.');
|
||||
} else {
|
||||
wp_send_json_error('Failed to delete files: ' . implode(', ', $errors));
|
||||
wp_send_json_error('Failed to delete files.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public function add_menu_item() {
|
||||
add_menu_page(
|
||||
'Audio Diary', // عنوان صفحه
|
||||
'Audio Diary', // عنوان منو
|
||||
'manage_options', // سطح دسترسی
|
||||
'audio-diary', // اسلاگ صفحه
|
||||
array($this, 'render_page'), // تابعی که محتوای صفحه را نمایش میدهد
|
||||
'dashicons-media-audio', // آیکون منو
|
||||
6
|
||||
'Audio Diary',
|
||||
'Audio Diary',
|
||||
'manage_options',
|
||||
'audio-diary',
|
||||
array($this, 'render_page'),
|
||||
'dashicons-media-audio',
|
||||
6
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
|
|
@ -181,22 +285,33 @@ class Audio_Diary_Admin_Page {
|
|||
'audio-diary-list',
|
||||
array($this, 'render_list_page')
|
||||
);
|
||||
add_submenu_page(
|
||||
'audio-diary',
|
||||
__('setting', 'audio-diary'),
|
||||
__('setting', 'audio-diary'),
|
||||
'manage_options',
|
||||
'setting',
|
||||
array($this, 'setting_page')
|
||||
);
|
||||
}
|
||||
|
||||
public function enqueue_scripts() {
|
||||
wp_enqueue_style('audio-diary-style', plugin_dir_url(__FILE__) . '../assets/css/style.css');
|
||||
wp_enqueue_style('audio-diary-toast-style', plugin_dir_url(__FILE__) . '../assets/css/jquery.toast.css');
|
||||
wp_enqueue_script('audio-diary-script', plugin_dir_url(__FILE__) ."../assets/js/audio-diary.js", array('jquery'), '1.0', true);
|
||||
wp_enqueue_script('audio-diary-toast-script', plugin_dir_url(__FILE__) ."../assets/js/jquery.toast.js", array('jquery'), '1.0', true);
|
||||
|
||||
wp_enqueue_script('audio-diary-script', plugin_dir_url(__FILE__) . "../assets/js/audio-diary.js", array('jquery'), '1.0', true);
|
||||
wp_enqueue_script('audio-diary-toast-script', plugin_dir_url(__FILE__) . "../assets/js/jquery.toast.js", array('jquery'), '1.0', true);
|
||||
}
|
||||
|
||||
public function render_page() {
|
||||
include_once AUDIO_DIARY_MODULES_PATH."audio-diary-admin-page.php";
|
||||
include_once AUDIO_DIARY_MODULES_PATH . "audio-diary-admin-page.php";
|
||||
}
|
||||
|
||||
public function render_list_page() {
|
||||
include_once AUDIO_DIARY_MODULES_PATH."audio-diary-admin-list-page.php";
|
||||
include_once AUDIO_DIARY_MODULES_PATH . "audio-diary-admin-list-page.php";
|
||||
}
|
||||
|
||||
public function setting_page() {
|
||||
include_once AUDIO_DIARY_MODULES_PATH . "setting-admin-page.php";
|
||||
}
|
||||
|
||||
private function create_audio_folder() {
|
||||
|
|
@ -206,35 +321,33 @@ class Audio_Diary_Admin_Page {
|
|||
if (!file_exists($audio_dir)) {
|
||||
wp_mkdir_p($audio_dir);
|
||||
}
|
||||
}
|
||||
|
||||
public function save_audio() {
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_send_json_error('Unauthorized');
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($_FILES['audio_data'])) {
|
||||
wp_send_json_error('No file uploaded');
|
||||
return;
|
||||
}
|
||||
public function save_audio() {
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_send_json_error('Unauthorized');
|
||||
return;
|
||||
}
|
||||
|
||||
$file = $_FILES['audio_data'];
|
||||
$uploads = wp_upload_dir();
|
||||
$upload_path = $uploads['basedir'] . '/audio-diary/';
|
||||
if (empty($_FILES['audio_data'])) {
|
||||
wp_send_json_error('No file uploaded');
|
||||
return;
|
||||
}
|
||||
|
||||
$date_time = date('Y-m-d-H-i-s');
|
||||
$file_name = 'memory-' . $date_time . '.wav';
|
||||
$file_path = $upload_path . $file_name;
|
||||
$file = $_FILES['audio_data'];
|
||||
$uploads = wp_upload_dir();
|
||||
$upload_path = $uploads['basedir'] . '/audio-diary/';
|
||||
|
||||
if (move_uploaded_file($file['tmp_name'], $file_path)) {
|
||||
wp_send_json_success(['message' => 'File uploaded', 'file_name' => $file_name]);
|
||||
} else {
|
||||
wp_send_json_error('File upload failed');
|
||||
$date_time = date('Y-m-d-H-i-s');
|
||||
$file_name = 'memory-' . $date_time . '.wav';
|
||||
$file_path = $upload_path . $file_name;
|
||||
|
||||
if (move_uploaded_file($file['tmp_name'], $file_path)) {
|
||||
wp_send_json_success(['message' => 'File uploaded', 'file_name' => $file_name]);
|
||||
} else {
|
||||
wp_send_json_error('File upload failed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Audio_Diary_Admin_Page::get_instance();
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"require": {
|
||||
"google/apiclient": "^2.0"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -14,36 +14,42 @@ usort($audio_files, function($a, $b) {
|
|||
?>
|
||||
<div class="wrap audio-diary-admin-list-page">
|
||||
<h1><?php _e('Recorded Audios', 'audio-diary'); ?></h1>
|
||||
<button id="delete-selected"><?php _e('Delete Selected', 'audio-diary'); ?></button>
|
||||
<button id="download-zip"><?php _e('Download Selected as ZIP', 'audio-diary'); ?></button>
|
||||
<button id="select-all" data-select-all="true">Select All</button>
|
||||
<table>
|
||||
<div class="action-buttons">
|
||||
<button id="delete-selected" class="btn btn-danger"><?php _e('Delete Selected', 'audio-diary'); ?></button>
|
||||
<button id="download-zip"
|
||||
class="btn btn-primary"><?php _e('Download Selected as ZIP', 'audio-diary'); ?></button>
|
||||
<button id="select-all" class="btn btn-secondary" data-select-all="true">Select All</button>
|
||||
</div>
|
||||
<div id="selected-count" class="selected-count">Selected: 0</div>
|
||||
<table id="audio-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('Select', 'audio-diary'); ?></th>
|
||||
<th><?php _e('Date', 'audio-diary'); ?></th>
|
||||
<th><?php _e('Time', 'audio-diary'); ?></th>
|
||||
<th><?php _e('Audio', 'audio-diary'); ?></th>
|
||||
<th><?php _e('Delete', 'audio-diary'); ?></th>
|
||||
<th><?php _e('Actions', 'audio-diary'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($audio_files as $file) :
|
||||
$file_date = jdate("Y-m-d", filemtime($file)); // تبدیل به تاریخ شمسی
|
||||
$file_time = jdate("H:i:s", filemtime($file)); // زمان را به همان صورت نمایش میدهیم
|
||||
$file_date = jdate("Y-m-d", filemtime($file));
|
||||
$file_time = jdate("H:i:s", filemtime($file));
|
||||
$file_url = $uploads['baseurl'] . '/audio-diary/' . basename($file);
|
||||
$file_name = basename($file);
|
||||
?>
|
||||
<tr>
|
||||
<tr data-file="<?php echo $file_name; ?>">
|
||||
<td><input type="checkbox" class="select-audio" value="<?php echo $file_name; ?>"></td>
|
||||
<td><?php echo $file_date; ?></td>
|
||||
<td><?php echo $file_time; ?></td>
|
||||
<td>
|
||||
<audio controls src="<?php echo $file_url; ?>"></audio>
|
||||
</td>
|
||||
<td>
|
||||
<button class="delete-audio"
|
||||
data-file="<?php echo $file_name; ?>"><?php _e('Delete', 'audio-diary'); ?></button>
|
||||
<td class="action-cell">
|
||||
<button class="btn btn-small btn-download download-single" data-url="<?php echo $file_url; ?>"
|
||||
data-name="<?php echo $file_name; ?>">Download</button>
|
||||
<button class="btn btn-small btn-upload upload-to-drive"
|
||||
data-name="<?php echo $file_name; ?>">Upload to Drive</button>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,224 @@
|
|||
<?php
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class AudioDiarySettings {
|
||||
private $folder_id_option = 'audio_diary_google_drive_folder_id';
|
||||
private $default_folder_id = '1sBE78fuxRlcWouLs0mw12zLqTbWJg9jB';
|
||||
|
||||
public function render() {
|
||||
if (isset($_POST['audio_diary_settings_submit']) && check_admin_referer('audio_diary_settings_nonce')) {
|
||||
$new_folder_id = sanitize_text_field($_POST['google_drive_folder_id']);
|
||||
update_option($this->folder_id_option, $new_folder_id);
|
||||
echo '<div class="notice notice-success is-dismissible"><p>' . __('Settings saved successfully!', 'audio-diary') . '</p></div>';
|
||||
}
|
||||
|
||||
$folder_id = get_option($this->folder_id_option, $this->default_folder_id);
|
||||
$folder_info = $this->get_folder_info($folder_id);
|
||||
?>
|
||||
|
||||
<div class="wrap audio-diary-settings">
|
||||
<h1><?php _e('Audio Diary Settings', 'audio-diary'); ?></h1>
|
||||
<p class="description"><?php _e('Configure the settings for your Audio Diary plugin below.', 'audio-diary'); ?></p>
|
||||
|
||||
<h2 class="nav-tab-wrapper">
|
||||
<a href="#general" class="nav-tab nav-tab-active"><?php _e('General', 'audio-diary'); ?></a>
|
||||
</h2>
|
||||
|
||||
<form method="post" action="" class="audio-diary-settings-form">
|
||||
<?php wp_nonce_field('audio_diary_settings_nonce'); ?>
|
||||
|
||||
<div class="settings-section">
|
||||
<h2><?php _e('Google Drive Settings', 'audio-diary'); ?></h2>
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label
|
||||
for="google_drive_folder_id"><?php _e('Google Drive Folder ID', 'audio-diary'); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" id="google_drive_folder_id" name="google_drive_folder_id"
|
||||
value="<?php echo esc_attr($folder_id); ?>" class="regular-text"
|
||||
placeholder="<?php _e('Enter Folder ID', 'audio-diary'); ?>" />
|
||||
<p class="description">
|
||||
<?php _e('The ID of the Google Drive folder where audio files are stored.', 'audio-diary'); ?>
|
||||
</p>
|
||||
<button type="button" id="test-connection"
|
||||
class="button"><?php _e('Test Connection', 'audio-diary'); ?></button>
|
||||
<span id="connection-status" class="connection-status"></span>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if ($folder_info): ?>
|
||||
<tr>
|
||||
<th scope="row"><?php _e('Folder Name', 'audio-diary'); ?></th>
|
||||
<td>
|
||||
<span class="folder-info"><?php echo esc_html($folder_info['name']); ?></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e('Folder URL', 'audio-diary'); ?></th>
|
||||
<td>
|
||||
<a href="<?php echo esc_url($folder_info['url']); ?>"
|
||||
target="_blank"><?php _e('Open in Google Drive', 'audio-diary'); ?></a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<tr>
|
||||
<th scope="row"><?php _e('Folder Status', 'audio-diary'); ?></th>
|
||||
<td>
|
||||
<span
|
||||
class="error"><?php _e('Folder not found or inaccessible. Verify the Folder ID and ensure it\'s shared with the Service Account.', 'audio-diary'); ?></span>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p class="submit">
|
||||
<input type="submit" name="audio_diary_settings_submit" class="button button-primary"
|
||||
value="<?php _e('Save Changes', 'audio-diary'); ?>" />
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.audio-diary-settings {
|
||||
max-width: 800px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.nav-tab-wrapper {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.settings-section {
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
border: 1px solid #ccd0d4;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, .04);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.settings-section h2 {
|
||||
margin-top: 0;
|
||||
font-size: 1.3em;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.form-table th {
|
||||
width: 200px;
|
||||
padding: 15px 10px;
|
||||
}
|
||||
|
||||
.form-table td {
|
||||
padding: 15px 10px;
|
||||
}
|
||||
|
||||
.folder-info {
|
||||
font-weight: bold;
|
||||
color: #23282d;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #d63638;
|
||||
}
|
||||
|
||||
.description {
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.submit {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#test-connection {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.connection-status {
|
||||
margin-left: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.connection-status.success {
|
||||
color: #46b450;
|
||||
}
|
||||
|
||||
.connection-status.error {
|
||||
color: #d63638;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
jQuery(document).ready(function($) {
|
||||
$('.nav-tab').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
$('.nav-tab').removeClass('nav-tab-active');
|
||||
$(this).addClass('nav-tab-active');
|
||||
});
|
||||
|
||||
$('#test-connection').on('click', function() {
|
||||
var $button = $(this);
|
||||
var folderId = $('#google_drive_folder_id').val();
|
||||
var $status = $('#connection-status');
|
||||
|
||||
$button.prop('disabled', true);
|
||||
$status.text('<?php _e("Testing...", "audio-diary"); ?>').removeClass('success error');
|
||||
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'audio_diary_test_connection',
|
||||
folder_id: folderId,
|
||||
nonce: '<?php echo wp_create_nonce("audio_diary_test_connection_nonce"); ?>'
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
$status.text('<?php _e("Connection successful!", "audio-diary"); ?>')
|
||||
.addClass('success');
|
||||
} else {
|
||||
$status.text(response.data ||
|
||||
'<?php _e("Connection failed.", "audio-diary"); ?>').addClass(
|
||||
'error');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$status.text('<?php _e("AJAX error. Please try again.", "audio-diary"); ?>')
|
||||
.addClass('error');
|
||||
},
|
||||
complete: function() {
|
||||
$button.prop('disabled', false);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
private function get_folder_info($folder_id) {
|
||||
try {
|
||||
require_once plugin_dir_path(__FILE__) . '../vendor/autoload.php';
|
||||
$client = new Google_Client();
|
||||
$client->setAuthConfig(plugin_dir_path(__FILE__) . '../config/service-account.json');
|
||||
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY); // تغییر Scope
|
||||
$service = new Google_Service_Drive($client);
|
||||
|
||||
$folder = $service->files->get($folder_id, ['fields' => 'id,name,webViewLink']);
|
||||
return [
|
||||
'name' => $folder->getName(),
|
||||
'url' => $folder->getWebViewLink()
|
||||
];
|
||||
} catch (Exception $e) {
|
||||
error_log("Failed to get folder info for $folder_id: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$settings = new AudioDiarySettings();
|
||||
$settings->render();
|
||||
?>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, $err);
|
||||
} elseif (!headers_sent()) {
|
||||
echo $err;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
$err,
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit3e6e79e410cd98a8d86f36f772fe3690::getLoader();
|
||||
|
|
@ -0,0 +1,579 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see https://www.php-fig.org/psr/psr-0/
|
||||
* @see https://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/** @var \Closure(string):void */
|
||||
private static $includeFile;
|
||||
|
||||
/** @var string|null */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array<string, list<string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* List of PSR-0 prefixes
|
||||
*
|
||||
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
|
||||
*
|
||||
* @var array<string, array<string, list<string>>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
/** @var bool */
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
/** @var bool */
|
||||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var string|null */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var array<string, self>
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param string|null $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
$this->vendorDir = $vendorDir;
|
||||
self::initializeIncludeClosure();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> Array of classname => path
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $classMap Class to filename map
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
|
||||
if (null === $this->vendorDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($prepend) {
|
||||
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||
} else {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
|
||||
if (null !== $this->vendorDir) {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return true|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
$includeFile = self::$includeFile;
|
||||
$includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently registered loaders keyed by their corresponding vendor directories.
|
||||
*
|
||||
* @return array<string, self>
|
||||
*/
|
||||
public static function getRegisteredLoaders()
|
||||
{
|
||||
return self::$registeredLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $ext
|
||||
* @return string|false
|
||||
*/
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
$subPath = $class;
|
||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||
$subPath = substr($subPath, 0, $lastPos);
|
||||
$search = $subPath . '\\';
|
||||
if (isset($this->prefixDirsPsr4[$search])) {
|
||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||
if (file_exists($file = $dir . $pathEnd)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private static function initializeIncludeClosure()
|
||||
{
|
||||
if (self::$includeFile !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
*/
|
||||
self::$includeFile = \Closure::bind(static function($file) {
|
||||
include $file;
|
||||
}, null, null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,378 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Composer\Semver\VersionParser;
|
||||
|
||||
/**
|
||||
* This class is copied in every Composer installed project and available to all
|
||||
*
|
||||
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||
*
|
||||
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class InstalledVersions
|
||||
{
|
||||
/**
|
||||
* @var mixed[]|null
|
||||
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private static $installedIsLocalDir;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
private static $canGetVendors;
|
||||
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static $installedByVendor = array();
|
||||
|
||||
/**
|
||||
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||
*
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackages()
|
||||
{
|
||||
$packages = array();
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
$packages[] = array_keys($installed['versions']);
|
||||
}
|
||||
|
||||
if (1 === \count($packages)) {
|
||||
return $packages[0];
|
||||
}
|
||||
|
||||
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all package names with a specific type e.g. 'library'
|
||||
*
|
||||
* @param string $type
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackagesByType($type)
|
||||
{
|
||||
$packagesByType = array();
|
||||
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
foreach ($installed['versions'] as $name => $package) {
|
||||
if (isset($package['type']) && $package['type'] === $type) {
|
||||
$packagesByType[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $packagesByType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package is installed
|
||||
*
|
||||
* This also returns true if the package name is provided or replaced by another package
|
||||
*
|
||||
* @param string $packageName
|
||||
* @param bool $includeDevRequirements
|
||||
* @return bool
|
||||
*/
|
||||
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (isset($installed['versions'][$packageName])) {
|
||||
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package satisfies a version constraint
|
||||
*
|
||||
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||
*
|
||||
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||
*
|
||||
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||
* @param string $packageName
|
||||
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||
* @return bool
|
||||
*/
|
||||
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||
{
|
||||
$constraint = $parser->parseConstraints((string) $constraint);
|
||||
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||
|
||||
return $provided->matches($constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||
*
|
||||
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||
* whether a given version of a package is installed, and not just whether it exists
|
||||
*
|
||||
* @param string $packageName
|
||||
* @return string Version constraint usable with composer/semver
|
||||
*/
|
||||
public static function getVersionRanges($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ranges = array();
|
||||
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||
}
|
||||
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||
}
|
||||
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||
}
|
||||
|
||||
return implode(' || ', $ranges);
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getPrettyVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||
*/
|
||||
public static function getReference($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['reference'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||
*/
|
||||
public static function getInstallPath($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||
*/
|
||||
public static function getRootPackage()
|
||||
{
|
||||
$installed = self::getInstalled();
|
||||
|
||||
return $installed[0]['root'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw installed.php data for custom implementations
|
||||
*
|
||||
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||
* @return array[]
|
||||
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
|
||||
*/
|
||||
public static function getRawData()
|
||||
{
|
||||
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
self::$installed = include __DIR__ . '/installed.php';
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
return self::$installed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||
*
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
public static function getAllRawData()
|
||||
{
|
||||
return self::getInstalled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets you reload the static array from another file
|
||||
*
|
||||
* This is only useful for complex integrations in which a project needs to use
|
||||
* this class but then also needs to execute another project's autoloader in process,
|
||||
* and wants to ensure both projects have access to their version of installed.php.
|
||||
*
|
||||
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||
* the data it needs from this class, then call reload() with
|
||||
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||
* the project in which it runs can then also use this class safely, without
|
||||
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||
*
|
||||
* @param array[] $data A vendor/composer/installed.php data set
|
||||
* @return void
|
||||
*
|
||||
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||
*/
|
||||
public static function reload($data)
|
||||
{
|
||||
self::$installed = $data;
|
||||
self::$installedByVendor = array();
|
||||
|
||||
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
|
||||
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
|
||||
// so we have to assume it does not, and that may result in duplicate data being returned when listing
|
||||
// all installed packages for example
|
||||
self::$installedIsLocalDir = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static function getInstalled()
|
||||
{
|
||||
if (null === self::$canGetVendors) {
|
||||
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||
}
|
||||
|
||||
$installed = array();
|
||||
$copiedLocalDir = false;
|
||||
|
||||
if (self::$canGetVendors) {
|
||||
$selfDir = strtr(__DIR__, '\\', '/');
|
||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||
$vendorDir = strtr($vendorDir, '\\', '/');
|
||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir];
|
||||
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require $vendorDir.'/composer/installed.php';
|
||||
self::$installedByVendor[$vendorDir] = $required;
|
||||
$installed[] = $required;
|
||||
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
|
||||
self::$installed = $required;
|
||||
self::$installedIsLocalDir = true;
|
||||
}
|
||||
}
|
||||
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
|
||||
$copiedLocalDir = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require __DIR__ . '/installed.php';
|
||||
self::$installed = $required;
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
if (self::$installed !== array() && !$copiedLocalDir) {
|
||||
$installed[] = self::$installed;
|
||||
}
|
||||
|
||||
return $installed;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||
'Google_AccessToken_Revoke' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_AccessToken_Verify' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_AuthHandler_AuthHandlerFactory' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_AuthHandler_Guzzle6AuthHandler' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_AuthHandler_Guzzle7AuthHandler' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_Client' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_Collection' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_Exception' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_Http_Batch' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_Http_MediaFileUpload' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_Http_REST' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_Model' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_Service' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_Service_Exception' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_Service_Resource' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_Task_Composer' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_Task_Exception' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_Task_Retryable' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_Task_Runner' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
'Google_Utils_UriTemplate' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
);
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
// autoload_files.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
|
||||
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
|
||||
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
|
||||
'1f87db08236948d07391152dccb70f04' => $vendorDir . '/google/apiclient-services/autoload.php',
|
||||
'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
|
||||
'a8d3953fd9959404dd22d3dfcd0a79f0' => $vendorDir . '/google/apiclient/src/aliases.php',
|
||||
);
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'phpseclib3\\' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'),
|
||||
'Psr\\Log\\' => array($vendorDir . '/psr/log/src'),
|
||||
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
|
||||
'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),
|
||||
'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),
|
||||
'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'),
|
||||
'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
|
||||
'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
|
||||
'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
|
||||
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
|
||||
'Google\\Service\\' => array($vendorDir . '/google/apiclient-services/src'),
|
||||
'Google\\Auth\\' => array($vendorDir . '/google/auth/src'),
|
||||
'Google\\' => array($vendorDir . '/google/apiclient/src'),
|
||||
'Firebase\\JWT\\' => array($vendorDir . '/firebase/php-jwt/src'),
|
||||
);
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit3e6e79e410cd98a8d86f36f772fe3690
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Composer\Autoload\ClassLoader
|
||||
*/
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit3e6e79e410cd98a8d86f36f772fe3690', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit3e6e79e410cd98a8d86f36f772fe3690', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit3e6e79e410cd98a8d86f36f772fe3690::getInitializer($loader));
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
$filesToLoad = \Composer\Autoload\ComposerStaticInit3e6e79e410cd98a8d86f36f772fe3690::$files;
|
||||
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
|
||||
require $file;
|
||||
}
|
||||
}, null, null);
|
||||
foreach ($filesToLoad as $fileIdentifier => $file) {
|
||||
$requireFile($fileIdentifier, $file);
|
||||
}
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInit3e6e79e410cd98a8d86f36f772fe3690
|
||||
{
|
||||
public static $files = array (
|
||||
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
|
||||
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
|
||||
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
|
||||
'1f87db08236948d07391152dccb70f04' => __DIR__ . '/..' . '/google/apiclient-services/autoload.php',
|
||||
'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
|
||||
'a8d3953fd9959404dd22d3dfcd0a79f0' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
);
|
||||
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'p' =>
|
||||
array (
|
||||
'phpseclib3\\' => 11,
|
||||
),
|
||||
'P' =>
|
||||
array (
|
||||
'Psr\\Log\\' => 8,
|
||||
'Psr\\Http\\Message\\' => 17,
|
||||
'Psr\\Http\\Client\\' => 16,
|
||||
'Psr\\Cache\\' => 10,
|
||||
'ParagonIE\\ConstantTime\\' => 23,
|
||||
),
|
||||
'M' =>
|
||||
array (
|
||||
'Monolog\\' => 8,
|
||||
),
|
||||
'G' =>
|
||||
array (
|
||||
'GuzzleHttp\\Psr7\\' => 16,
|
||||
'GuzzleHttp\\Promise\\' => 19,
|
||||
'GuzzleHttp\\' => 11,
|
||||
'Google\\Service\\' => 15,
|
||||
'Google\\Auth\\' => 12,
|
||||
'Google\\' => 7,
|
||||
),
|
||||
'F' =>
|
||||
array (
|
||||
'Firebase\\JWT\\' => 13,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
'phpseclib3\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib',
|
||||
),
|
||||
'Psr\\Log\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/psr/log/src',
|
||||
),
|
||||
'Psr\\Http\\Message\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/psr/http-factory/src',
|
||||
1 => __DIR__ . '/..' . '/psr/http-message/src',
|
||||
),
|
||||
'Psr\\Http\\Client\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/psr/http-client/src',
|
||||
),
|
||||
'Psr\\Cache\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/psr/cache/src',
|
||||
),
|
||||
'ParagonIE\\ConstantTime\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src',
|
||||
),
|
||||
'Monolog\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/monolog/monolog/src/Monolog',
|
||||
),
|
||||
'GuzzleHttp\\Psr7\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src',
|
||||
),
|
||||
'GuzzleHttp\\Promise\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/guzzlehttp/promises/src',
|
||||
),
|
||||
'GuzzleHttp\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',
|
||||
),
|
||||
'Google\\Service\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/google/apiclient-services/src',
|
||||
),
|
||||
'Google\\Auth\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/google/auth/src',
|
||||
),
|
||||
'Google\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/google/apiclient/src',
|
||||
),
|
||||
'Firebase\\JWT\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/firebase/php-jwt/src',
|
||||
),
|
||||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||
'Google_AccessToken_Revoke' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_AccessToken_Verify' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_AuthHandler_AuthHandlerFactory' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_AuthHandler_Guzzle6AuthHandler' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_AuthHandler_Guzzle7AuthHandler' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_Client' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_Collection' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_Exception' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_Http_Batch' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_Http_MediaFileUpload' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_Http_REST' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_Model' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_Service' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_Service_Exception' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_Service_Resource' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_Task_Composer' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_Task_Exception' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_Task_Retryable' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_Task_Runner' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
'Google_Utils_UriTemplate' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit3e6e79e410cd98a8d86f36f772fe3690::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit3e6e79e410cd98a8d86f36f772fe3690::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInit3e6e79e410cd98a8d86f36f772fe3690::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,209 @@
|
|||
<?php return array(
|
||||
'root' => array(
|
||||
'name' => '__root__',
|
||||
'pretty_version' => 'dev-main',
|
||||
'version' => 'dev-main',
|
||||
'reference' => '97074b8725c52a7110cbc94b2f0a244672943834',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev' => true,
|
||||
),
|
||||
'versions' => array(
|
||||
'__root__' => array(
|
||||
'pretty_version' => 'dev-main',
|
||||
'version' => 'dev-main',
|
||||
'reference' => '97074b8725c52a7110cbc94b2f0a244672943834',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'firebase/php-jwt' => array(
|
||||
'pretty_version' => 'v6.11.0',
|
||||
'version' => '6.11.0.0',
|
||||
'reference' => '8f718f4dfc9c5d5f0c994cdfd103921b43592712',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../firebase/php-jwt',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'google/apiclient' => array(
|
||||
'pretty_version' => 'v2.18.2',
|
||||
'version' => '2.18.2.0',
|
||||
'reference' => 'd8d201ba8a189a3cd7fb34e4da569f2ed440eee7',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../google/apiclient',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'google/apiclient-services' => array(
|
||||
'pretty_version' => 'v0.396.0',
|
||||
'version' => '0.396.0.0',
|
||||
'reference' => 'ceb2e432e4326c6775d24f62d554395a1a9ad3dd',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../google/apiclient-services',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'google/auth' => array(
|
||||
'pretty_version' => 'v1.46.0',
|
||||
'version' => '1.46.0.0',
|
||||
'reference' => '7fafae99a41984cbfb92508174263cf7bf3049b9',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../google/auth',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'guzzlehttp/guzzle' => array(
|
||||
'pretty_version' => '7.9.2',
|
||||
'version' => '7.9.2.0',
|
||||
'reference' => 'd281ed313b989f213357e3be1a179f02196ac99b',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'guzzlehttp/promises' => array(
|
||||
'pretty_version' => '2.0.4',
|
||||
'version' => '2.0.4.0',
|
||||
'reference' => 'f9c436286ab2892c7db7be8c8da4ef61ccf7b455',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../guzzlehttp/promises',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'guzzlehttp/psr7' => array(
|
||||
'pretty_version' => '2.7.0',
|
||||
'version' => '2.7.0.0',
|
||||
'reference' => 'a70f5c95fb43bc83f07c9c948baa0dc1829bf201',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../guzzlehttp/psr7',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'monolog/monolog' => array(
|
||||
'pretty_version' => '3.8.1',
|
||||
'version' => '3.8.1.0',
|
||||
'reference' => 'aef6ee73a77a66e404dd6540934a9ef1b3c855b4',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../monolog/monolog',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'paragonie/constant_time_encoding' => array(
|
||||
'pretty_version' => 'v3.0.0',
|
||||
'version' => '3.0.0.0',
|
||||
'reference' => 'df1e7fde177501eee2037dd159cf04f5f301a512',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../paragonie/constant_time_encoding',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'paragonie/random_compat' => array(
|
||||
'pretty_version' => 'v9.99.100',
|
||||
'version' => '9.99.100.0',
|
||||
'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../paragonie/random_compat',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'phpseclib/phpseclib' => array(
|
||||
'pretty_version' => '3.0.43',
|
||||
'version' => '3.0.43.0',
|
||||
'reference' => '709ec107af3cb2f385b9617be72af8cf62441d02',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phpseclib/phpseclib',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'psr/cache' => array(
|
||||
'pretty_version' => '3.0.0',
|
||||
'version' => '3.0.0.0',
|
||||
'reference' => 'aa5030cfa5405eccfdcb1083ce040c2cb8d253bf',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../psr/cache',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'psr/http-client' => array(
|
||||
'pretty_version' => '1.0.3',
|
||||
'version' => '1.0.3.0',
|
||||
'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../psr/http-client',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'psr/http-client-implementation' => array(
|
||||
'dev_requirement' => false,
|
||||
'provided' => array(
|
||||
0 => '1.0',
|
||||
),
|
||||
),
|
||||
'psr/http-factory' => array(
|
||||
'pretty_version' => '1.1.0',
|
||||
'version' => '1.1.0.0',
|
||||
'reference' => '2b4765fddfe3b508ac62f829e852b1501d3f6e8a',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../psr/http-factory',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'psr/http-factory-implementation' => array(
|
||||
'dev_requirement' => false,
|
||||
'provided' => array(
|
||||
0 => '1.0',
|
||||
),
|
||||
),
|
||||
'psr/http-message' => array(
|
||||
'pretty_version' => '2.0',
|
||||
'version' => '2.0.0.0',
|
||||
'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../psr/http-message',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'psr/http-message-implementation' => array(
|
||||
'dev_requirement' => false,
|
||||
'provided' => array(
|
||||
0 => '1.0',
|
||||
),
|
||||
),
|
||||
'psr/log' => array(
|
||||
'pretty_version' => '3.0.2',
|
||||
'version' => '3.0.2.0',
|
||||
'reference' => 'f16e1d5863e37f8d8c2a01719f5b34baa2b714d3',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../psr/log',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'psr/log-implementation' => array(
|
||||
'dev_requirement' => false,
|
||||
'provided' => array(
|
||||
0 => '3.0.0',
|
||||
),
|
||||
),
|
||||
'ralouphie/getallheaders' => array(
|
||||
'pretty_version' => '3.0.3',
|
||||
'version' => '3.0.3.0',
|
||||
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../ralouphie/getallheaders',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'symfony/deprecation-contracts' => array(
|
||||
'pretty_version' => 'v3.5.1',
|
||||
'version' => '3.5.1.0',
|
||||
'reference' => '74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
// platform_check.php @generated by Composer
|
||||
|
||||
$issues = array();
|
||||
|
||||
if (!(PHP_VERSION_ID >= 80100)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.0". You are running ' . PHP_VERSION . '.';
|
||||
}
|
||||
|
||||
if ($issues) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||
} elseif (!headers_sent()) {
|
||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue