summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatarLibravatar Biswakalyan Bhuyan <biswa@surgot.in> 2024-06-28 12:31:31 +0530
committerLibravatarLibravatar Biswakalyan Bhuyan <biswa@surgot.in> 2024-06-28 12:31:31 +0530
commitc2025cfdf07a56859c447a4eac7e1546f4a168ae (patch)
treebb5c26c620f28059f1c447fb22473ab4e2f4f4ef
parentaf92d9f12534021ccb35e0328daec8fdc72c0ba2 (diff)
downloadinsta-local-c2025cfdf07a56859c447a4eac7e1546f4a168ae.tar.gz
insta-local-c2025cfdf07a56859c447a4eac7e1546f4a168ae.tar.bz2
insta-local-c2025cfdf07a56859c447a4eac7e1546f4a168ae.zip
arranged dir
-rw-r--r--.gitignore1
-rw-r--r--client/package-lock.json42
-rw-r--r--client/package.json1
-rw-r--r--client/src/App.js102
-rw-r--r--client/src/Influencers.css22
-rw-r--r--client/src/Influencers.js102
-rw-r--r--package-lock.json13
-rw-r--r--package.json1
-rw-r--r--server/download_script.py (renamed from download_script.py)2
-rw-r--r--server/server.js (renamed from server.js)47
10 files changed, 302 insertions, 31 deletions
diff --git a/.gitignore b/.gitignore
index 1a0b59b..494c48a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@ node_modules
downloads
credentials.json
influencers.json
+.env
diff --git a/client/package-lock.json b/client/package-lock.json
index a6aacf5..a6fa0c1 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -14,6 +14,7 @@
"axios": "^1.7.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
+ "react-router-dom": "^6.24.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}
@@ -3562,6 +3563,15 @@
}
}
},
+ "node_modules/@remix-run/router": {
+ "version": "1.17.0",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.0.tgz",
+ "integrity": "sha512-2D6XaHEVvkCn682XBnipbJjgZUU7xjLtA4dGJRBVUKpEaDYOZMENZoZjAOSb7qirxt5RupjzZxz4fK2FO+EFPw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -16288,6 +16298,38 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-router": {
+ "version": "6.24.0",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.24.0.tgz",
+ "integrity": "sha512-sQrgJ5bXk7vbcC4BxQxeNa5UmboFm35we1AFK0VvQaz9g0LzxEIuLOhHIoZ8rnu9BO21ishGeL9no1WB76W/eg==",
+ "license": "MIT",
+ "dependencies": {
+ "@remix-run/router": "1.17.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "6.24.0",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.24.0.tgz",
+ "integrity": "sha512-960sKuau6/yEwS8e+NVEidYQb1hNjAYM327gjEyXlc6r3Skf2vtwuJ2l7lssdegD2YjoKG5l8MsVyeTDlVeY8g==",
+ "license": "MIT",
+ "dependencies": {
+ "@remix-run/router": "1.17.0",
+ "react-router": "6.24.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
+ }
+ },
"node_modules/react-scripts": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
diff --git a/client/package.json b/client/package.json
index b660797..70e70ca 100644
--- a/client/package.json
+++ b/client/package.json
@@ -9,6 +9,7 @@
"axios": "^1.7.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
+ "react-router-dom": "^6.24.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
diff --git a/client/src/App.js b/client/src/App.js
index eaeca2c..2d19281 100644
--- a/client/src/App.js
+++ b/client/src/App.js
@@ -1,9 +1,13 @@
import React, { useEffect, useState } from 'react';
+import { BrowserRouter as Router, Route, Link, Routes } from 'react-router-dom';
import axios from 'axios';
import './App.css';
+import Influencers from './Influencers';
function App() {
const [downloadedFiles, setDownloadedFiles] = useState([]);
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
+ const [adminPassword, setAdminPassword] = useState('');
useEffect(() => {
fetchDownloadedFiles();
@@ -22,35 +26,79 @@ function App() {
}
};
+ const handleLogin = (password) => {
+ setAdminPassword(password);
+ setIsAuthenticated(true);
+ };
+
return (
- <div className="App">
- <header className="App-header">
- <h1 className="App-title">Insta Local</h1>
- <div className="downloaded-content">
- {downloadedFiles.length === 0 ? (
- <p>No content available</p>
- ) : (
- downloadedFiles.map((file, index) => {
- const fileUrl = `http://localhost:5001/static/${file}`;
- console.log('Fetching file:', fileUrl); // Log the file URL
- return (
- <div key={index} className="file-item">
- {file.endsWith('.mp4') ? (
- <video controls>
- <source src={fileUrl} type="video/mp4" />
- Your browser does not support the video tag.
- </video>
- ) : (
- <img src={fileUrl} alt={file} />
- )}
- </div>
- );
- })
- )}
- </div>
- </header>
- </div>
+ <Router>
+ <div className="App">
+ <header className="App-header">
+ <h1 className="App-title">Insta Local</h1>
+ <nav>
+ <Link to="/">Home</Link>
+ <Link to="/influencers">Add Influencers</Link>
+ </nav>
+ </header>
+ <Routes>
+ <Route path="/" element={
+ <div className="downloaded-content">
+ {downloadedFiles.length === 0 ? (
+ <p>No content available</p>
+ ) : (
+ downloadedFiles.map((file, index) => {
+ const fileUrl = `http://localhost:5001/static/${file}`;
+ return (
+ <div key={index} className="file-item">
+ {file.endsWith('.mp4') ? (
+ <video controls>
+ <source src={fileUrl} type="video/mp4" />
+ Your browser does not support the video tag.
+ </video>
+ ) : (
+ <img src={fileUrl} alt={file} />
+ )}
+ </div>
+ );
+ })
+ )}
+ </div>
+ } />
+ <Route path="/influencers" element={
+ isAuthenticated ? (
+ <Influencers adminPassword={adminPassword} />
+ ) : (
+ <Login onLogin={handleLogin} />
+ )
+ } />
+ </Routes>
+ </div>
+ </Router>
);
}
+const Login = ({ onLogin }) => {
+ const [password, setPassword] = useState('');
+
+ const handleSubmit = (event) => {
+ event.preventDefault();
+ onLogin(password);
+ };
+
+ return (
+ <form onSubmit={handleSubmit}>
+ <label>
+ Password:
+ <input
+ type="password"
+ value={password}
+ onChange={(e) => setPassword(e.target.value)}
+ />
+ </label>
+ <button type="submit">Login</button>
+ </form>
+ );
+};
+
export default App;
diff --git a/client/src/Influencers.css b/client/src/Influencers.css
new file mode 100644
index 0000000..443762e
--- /dev/null
+++ b/client/src/Influencers.css
@@ -0,0 +1,22 @@
+.influencers {
+ padding: 20px;
+}
+
+.password-input, .add-profile, .export-import {
+ margin-bottom: 20px;
+}
+
+.profile-list ul {
+ list-style-type: none;
+ padding: 0;
+}
+
+.profile-list li {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 10px;
+}
+
+button {
+ margin-left: 10px;
+}
diff --git a/client/src/Influencers.js b/client/src/Influencers.js
new file mode 100644
index 0000000..a72d654
--- /dev/null
+++ b/client/src/Influencers.js
@@ -0,0 +1,102 @@
+import React, { useState, useEffect, useCallback } from 'react';
+import axios from 'axios';
+
+function Influencers({ adminPassword }) {
+ const [profiles, setProfiles] = useState([]);
+ const [newProfile, setNewProfile] = useState('');
+
+ const fetchProfiles = useCallback(async () => {
+ try {
+ const response = await axios.get('http://localhost:5001/profiles', {
+ headers: { Authorization: `Bearer ${adminPassword}` }
+ });
+ console.log('Fetched profiles:', response.data);
+ setProfiles(response.data);
+ } catch (error) {
+ console.error('Error fetching profiles:', error);
+ }
+ }, [adminPassword]);
+
+ useEffect(() => {
+ fetchProfiles();
+ }, [fetchProfiles]);
+
+ const addProfile = async () => {
+ try {
+ await axios.post(
+ 'http://localhost:5001/profiles',
+ { username: newProfile },
+ { headers: { Authorization: `Bearer ${adminPassword}` } }
+ );
+ setNewProfile('');
+ fetchProfiles();
+ } catch (error) {
+ console.error('Error adding profile:', error);
+ }
+ };
+
+ const handleJsonUpload = async (event) => {
+ const file = event.target.files[0];
+ if (file) {
+ const formData = new FormData();
+ formData.append('file', file);
+
+ try {
+ await axios.post('http://localhost:5001/upload', formData, {
+ headers: {
+ 'Content-Type': 'multipart/form-data',
+ Authorization: `Bearer ${adminPassword}`
+ }
+ });
+ fetchProfiles();
+ } catch (error) {
+ console.error('Error uploading JSON file:', error);
+ }
+ }
+ };
+
+ const exportJson = async () => {
+ try {
+ const response = await axios.get('http://localhost:5001/export', {
+ headers: { Authorization: `Bearer ${adminPassword}` },
+ responseType: 'blob'
+ });
+ const url = window.URL.createObjectURL(new Blob([response.data]));
+ const link = document.createElement('a');
+ link.href = url;
+ link.setAttribute('download', 'influencers.json');
+ document.body.appendChild(link);
+ link.click();
+ } catch (error) {
+ console.error('Error exporting JSON file:', error);
+ }
+ };
+
+ return (
+ <div>
+ <h2>Add Influencers</h2>
+ <input
+ type="text"
+ value={newProfile}
+ onChange={(e) => setNewProfile(e.target.value)}
+ placeholder="Enter Instagram username"
+ />
+ <button onClick={addProfile}>Add</button>
+ <h3>Current Influencers</h3>
+ <ul>
+ {profiles.map((profile, index) => (
+ <li key={index}>{profile}</li>
+ ))}
+ </ul>
+ <h3>Import/Export Influencers</h3>
+ <input
+ type="file"
+ accept="application/json"
+ onChange={handleJsonUpload}
+ />
+ <button onClick={exportJson}>Export JSON</button>
+ </div>
+ );
+}
+
+export default Influencers;
diff --git a/package-lock.json b/package-lock.json
index 1e51c34..773fac2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,6 +11,7 @@
"dependencies": {
"axios": "^1.7.2",
"cors": "^2.8.5",
+ "dotenv": "^16.4.5",
"express": "^4.19.2",
"instaloader": "^1.0.1",
"node-cron": "^3.0.3"
@@ -219,6 +220,18 @@
"npm": "1.2.8000 || >= 1.4.16"
}
},
+ "node_modules/dotenv": {
+ "version": "16.4.5",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
+ "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
diff --git a/package.json b/package.json
index 9353b5e..b7e2b30 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
"dependencies": {
"axios": "^1.7.2",
"cors": "^2.8.5",
+ "dotenv": "^16.4.5",
"express": "^4.19.2",
"instaloader": "^1.0.1",
"node-cron": "^3.0.3"
diff --git a/download_script.py b/server/download_script.py
index a9d07c4..d6e03bc 100644
--- a/download_script.py
+++ b/server/download_script.py
@@ -5,7 +5,7 @@ import os
L = instaloader.Instaloader()
L.login('xtester2', 'teTeD7QojvhOdvEGa50u6FFJo')
PROFILES = ["aao.remote.ho.jaye"]
-BASE_DIR = "/home/genos/imp/work/project/insta/downloads"
+BASE_DIR = "/home/genos/imp/work/project/insta/server/downloads"
os.makedirs(BASE_DIR, exist_ok=True)
diff --git a/server.js b/server/server.js
index 5727d34..b795846 100644
--- a/server.js
+++ b/server/server.js
@@ -1,14 +1,21 @@
+require('dotenv').config(); // Add this line at the top
const express = require('express');
const { exec } = require('child_process');
const path = require('path');
const cors = require('cors');
const fs = require('fs');
const cron = require('node-cron');
+const bodyParser = require('body-parser');
const app = express();
const port = 5001;
+const adminPassword = process.env.ADMIN_PASSWORD; // Use environment variable
+
app.use(express.json());
app.use(cors());
+app.use(bodyParser.json());
+
+const baseDir = path.join(__dirname, 'downloads');
function escapePythonString(str) {
return str.replace(/\\/g, '\\\\')
@@ -22,8 +29,6 @@ const credentials = JSON.parse(fs.readFileSync(path.join(__dirname, 'credentials
const escapedUsername = escapePythonString(credentials.username);
const escapedPassword = escapePythonString(credentials.password);
-const baseDir = path.join(__dirname, 'downloads');
-
function downloadContent() {
const influencers = JSON.parse(fs.readFileSync(path.join(__dirname, 'influencers.json'), 'utf8')).profiles;
@@ -79,7 +84,7 @@ app.get('/downloads', (req, res) => {
if (err) {
return res.status(500).json({ error: err.message });
}
- const allowedExtensions = ['.mp4', '.jpg', '.jpeg'];
+ const allowedExtensions = ['.mp4'];
const fileList = profiles.flatMap(profileDir => {
const profilePath = path.join(baseDir, profileDir);
return fs.readdirSync(profilePath)
@@ -97,6 +102,42 @@ app.get('/downloads', (req, res) => {
// Serve downloaded files statically
app.use('/static', express.static(path.join(__dirname, 'downloads')));
+// Authentication middleware
+const authenticate = (req, res, next) => {
+ const password = req.headers['x-admin-password'];
+ if (password === adminPassword) {
+ next();
+ } else {
+ res.status(401).json({ error: 'Unauthorized' });
+ }
+};
+
+// Endpoint to get influencers
+app.get('/influencers', authenticate, (req, res) => {
+ const influencers = JSON.parse(fs.readFileSync(path.join(__dirname, 'influencers.json'), 'utf8')).profiles;
+ res.json(influencers);
+});
+
+// Endpoint to update influencers
+app.post('/influencers', authenticate, (req, res) => {
+ const { profiles } = req.body;
+ fs.writeFileSync(path.join(__dirname, 'influencers.json'), JSON.stringify({ profiles }, null, 2));
+ res.status(200).json({ message: 'Influencers updated successfully' });
+});
+
+// Endpoint to export influencers JSON
+app.get('/export-influencers', authenticate, (req, res) => {
+ const influencers = JSON.parse(fs.readFileSync(path.join(__dirname, 'influencers.json'), 'utf8'));
+ res.json(influencers);
+});
+
+// Endpoint to import influencers JSON
+app.post('/import-influencers', authenticate, (req, res) => {
+ const { profiles } = req.body;
+ fs.writeFileSync(path.join(__dirname, 'influencers.json'), JSON.stringify({ profiles }, null, 2));
+ res.status(200).json({ message: 'Influencers imported successfully' });
+});
+
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});