summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--client/src/App.css39
-rw-r--r--client/src/App.js57
-rw-r--r--download_script.py24
-rw-r--r--package-lock.json24
-rw-r--r--package.json3
-rw-r--r--server.js97
7 files changed, 184 insertions, 63 deletions
diff --git a/.gitignore b/.gitignore
index 3c3629e..1a0b59b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,4 @@
node_modules
+downloads
+credentials.json
+influencers.json
diff --git a/client/src/App.css b/client/src/App.css
index 74b5e05..f27a513 100644
--- a/client/src/App.css
+++ b/client/src/App.css
@@ -2,37 +2,30 @@
text-align: center;
}
-.App-logo {
- height: 40vmin;
- pointer-events: none;
+.App-header {
+ background-color: #282c34;
+ padding: 20px;
+ color: white;
}
-@media (prefers-reduced-motion: no-preference) {
- .App-logo {
- animation: App-logo-spin infinite 20s linear;
- }
+.App-title {
+ font-size: 1.5rem; /* Smaller heading */
}
-.App-header {
- background-color: #282c34;
- min-height: 100vh;
+.downloaded-content {
display: flex;
- flex-direction: column;
- align-items: center;
+ flex-wrap: wrap;
justify-content: center;
- font-size: calc(10px + 2vmin);
- color: white;
}
-.App-link {
- color: #61dafb;
+.file-item {
+ margin: 10px;
}
-@keyframes App-logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
+video, img {
+ max-width: 300px;
+ max-height: 300px;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ padding: 5px;
}
diff --git a/client/src/App.js b/client/src/App.js
index 3784575..eaeca2c 100644
--- a/client/src/App.js
+++ b/client/src/App.js
@@ -1,22 +1,53 @@
-import logo from './logo.svg';
+import React, { useEffect, useState } from 'react';
+import axios from 'axios';
import './App.css';
function App() {
+ const [downloadedFiles, setDownloadedFiles] = useState([]);
+
+ useEffect(() => {
+ fetchDownloadedFiles();
+ const interval = setInterval(() => {
+ fetchDownloadedFiles();
+ }, 60000); // Fetch new content every minute
+ return () => clearInterval(interval);
+ }, []);
+
+ const fetchDownloadedFiles = async () => {
+ try {
+ const response = await axios.get('http://localhost:5001/downloads');
+ setDownloadedFiles(response.data);
+ } catch (error) {
+ console.error('Error fetching downloaded files:', error);
+ }
+ };
+
return (
<div className="App">
<header className="App-header">
- <img src={logo} className="App-logo" alt="logo" />
- <p>
- Edit <code>src/App.js</code> and save to reload.
- </p>
- <a
- className="App-link"
- href="https://reactjs.org"
- target="_blank"
- rel="noopener noreferrer"
- >
- Learn React
- </a>
+ <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>
);
diff --git a/download_script.py b/download_script.py
new file mode 100644
index 0000000..be29fcc
--- /dev/null
+++ b/download_script.py
@@ -0,0 +1,24 @@
+
+import instaloader
+import os
+
+L = instaloader.Instaloader()
+L.login('xtester2', 'teTeD7QojvhOdvEGa50u6FFJo')
+PROFILES = ["aao.remote.ho.jaye"]
+BASE_DIR = "/home/genos/imp/work/project/insta/downloads/2024-06-27"
+
+os.makedirs(BASE_DIR, exist_ok=True)
+
+def download_posts(profile):
+ profile_dir = os.path.join(BASE_DIR, profile)
+ os.makedirs(profile_dir, exist_ok=True)
+ L.dirname_pattern = profile_dir
+ posts = instaloader.Profile.from_username(L.context, profile).get_posts()
+ for post in posts:
+ if post.typename == 'GraphVideo': # Only download videos
+ L.download_post(post, target=profile)
+ elif post.typename == 'GraphImage': # Only download images
+ L.download_post(post, target=profile)
+
+for profile in PROFILES:
+ download_posts(profile)
diff --git a/package-lock.json b/package-lock.json
index bc971fe..1e51c34 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,7 +12,8 @@
"axios": "^1.7.2",
"cors": "^2.8.5",
"express": "^4.19.2",
- "instaloader": "^1.0.1"
+ "instaloader": "^1.0.1",
+ "node-cron": "^3.0.3"
}
},
"node_modules/accepts": {
@@ -590,6 +591,18 @@
"node": ">= 0.6"
}
},
+ "node_modules/node-cron": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.3.tgz",
+ "integrity": "sha512-dOal67//nohNgYWb+nWmg5dkFdIwDm8EpeGYMekPMrngV3637lqnX0lbUcCtgibHTz6SEz7DAIjKvKDFYCnO1A==",
+ "license": "ISC",
+ "dependencies": {
+ "uuid": "8.3.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -857,6 +870,15 @@
"node": ">= 0.4.0"
}
},
+ "node_modules/uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
diff --git a/package.json b/package.json
index fe1e522..9353b5e 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"axios": "^1.7.2",
"cors": "^2.8.5",
"express": "^4.19.2",
- "instaloader": "^1.0.1"
+ "instaloader": "^1.0.1",
+ "node-cron": "^3.0.3"
}
}
diff --git a/server.js b/server.js
index 5c5a85d..c8dd2e4 100644
--- a/server.js
+++ b/server.js
@@ -2,56 +2,103 @@ 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 app = express();
-const port = 5000;
+const port = 5001;
app.use(express.json());
app.use(cors());
-app.post('/download', (req, res) => {
- const profiles = req.body.profiles;
- const baseDir = path.join(__dirname, 'downloads');
- const dateStr = new Date().toISOString().split('T')[0];
- const dateDir = path.join(baseDir, dateStr);
+function escapePythonString(str) {
+ return str.replace(/\\/g, '\\\\')
+ .replace(/'/g, "\\'")
+ .replace(/\n/g, '\\n')
+ .replace(/\t/g, '\\t');
+}
+
+// Read credentials from JSON file
+const credentials = JSON.parse(fs.readFileSync(path.join(__dirname, 'credentials.json'), 'utf8'));
+const escapedUsername = escapePythonString(credentials.username);
+const escapedPassword = escapePythonString(credentials.password);
+
+const baseDir = path.join(__dirname, 'downloads');
+const dateStr = new Date().toISOString().split('T')[0];
+const dateDir = path.join(baseDir, dateStr);
+
+function downloadContent() {
+ const influencers = JSON.parse(fs.readFileSync(path.join(__dirname, 'influencers.json'), 'utf8')).profiles;
const script = `
- import instaloader
- import os
+import instaloader
+import os
- L = instaloader.Instaloader()
- PROFILES = ${JSON.stringify(profiles)}
- BASE_DIR = "${dateDir.replace(/\\/g, '/')}"
+L = instaloader.Instaloader()
+L.login('${escapedUsername}', '${escapedPassword}')
+PROFILES = ${JSON.stringify(influencers)}
+BASE_DIR = "${dateDir.replace(/\\/g, '/')}"
- os.makedirs(BASE_DIR, exist_ok=True)
+os.makedirs(BASE_DIR, exist_ok=True)
- def download_posts(profile):
- profile_dir = os.path.join(BASE_DIR, profile)
- os.makedirs(profile_dir, exist_ok=True)
- L.dirname_pattern = profile_dir
- posts = instaloader.Profile.from_username(L.context, profile).get_posts()
- for post in posts:
+def download_posts(profile):
+ profile_dir = os.path.join(BASE_DIR, profile)
+ os.makedirs(profile_dir, exist_ok=True)
+ L.dirname_pattern = profile_dir
+ posts = instaloader.Profile.from_username(L.context, profile).get_posts()
+ for post in posts:
+ if post.typename == 'GraphVideo': # Only download videos
+ L.download_post(post, target=profile)
+ elif post.typename == 'GraphImage': # Only download images
L.download_post(post, target=profile)
- for profile in PROFILES:
- download_posts(profile)
- `;
+for profile in PROFILES:
+ download_posts(profile)
+`;
const scriptPath = path.join(__dirname, 'download_script.py');
- require('fs').writeFileSync(scriptPath, script);
+ fs.writeFileSync(scriptPath, script);
exec(`python3 ${scriptPath}`, (error, stdout, stderr) => {
if (error) {
console.error(`Error: ${error.message}`);
- return res.status(500).json({ error: error.message });
}
if (stderr) {
console.error(`Stderr: ${stderr}`);
- return res.status(500).json({ error: stderr });
}
- res.json({ message: 'Download complete', output: stdout });
+ console.log('Download complete');
+ });
+}
+
+// Schedule the download task to run every hour
+cron.schedule('0 * * * *', downloadContent);
+
+// Run the download task immediately on server start
+downloadContent();
+
+// Endpoint to list downloaded files
+app.get('/downloads', (req, res) => {
+ fs.readdir(dateDir, (err, profiles) => {
+ if (err) {
+ return res.status(500).json({ error: err.message });
+ }
+ const allowedExtensions = ['.mp4', '.jpg', '.jpeg'];
+ const fileList = profiles.flatMap(profileDir => {
+ const profilePath = path.join(dateDir, profileDir);
+ return fs.readdirSync(profilePath)
+ .filter(file => allowedExtensions.includes(path.extname(file).toLowerCase()))
+ .map(file => {
+ const filePath = path.join(profileDir, file);
+ console.log('Serving file:', filePath); // Log the file path
+ return filePath;
+ });
+ });
+ res.json(fileList);
});
});
+// Serve downloaded files statically
+app.use('/static', express.static(path.join(__dirname, 'downloads')));
+
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});