diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | client/src/App.css | 39 | ||||
-rw-r--r-- | client/src/App.js | 57 | ||||
-rw-r--r-- | download_script.py | 24 | ||||
-rw-r--r-- | package-lock.json | 24 | ||||
-rw-r--r-- | package.json | 3 | ||||
-rw-r--r-- | server.js | 97 |
7 files changed, 184 insertions, 63 deletions
@@ -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" } } @@ -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}`); }); |