diff --git a/.continue/rules/new-rule.md b/.continue/rules/new-rule.md new file mode 100644 index 0000000..f9554c7 --- /dev/null +++ b/.continue/rules/new-rule.md @@ -0,0 +1,5 @@ +--- +description: A description of your rule +--- + +Your rule content \ No newline at end of file diff --git a/bin/compress-videos-in-dir.ts b/bin/compress-videos-in-dir.ts index fb8e56f..235ab20 100755 --- a/bin/compress-videos-in-dir.ts +++ b/bin/compress-videos-in-dir.ts @@ -3,6 +3,8 @@ import {spawn} from 'child_process'; import {readdir} from 'fs/promises'; import {createInterface} from 'node:readline'; +import {runInBackground} from '../lib/ai-generated.ts'; +import { extname } from 'node:path'; function formatTime(seconds: number): string { @@ -39,9 +41,10 @@ async function getDuration(inputFile: string): Promise { }); } + async function compressVideo(inputFile: string, outputFile: string) { const duration = await getDuration(inputFile); - return new Promise(resolve => { + return new Promise((resolve, reject) => { try { const ffmpeg = spawn('ffmpeg', [ '-hwaccel', 'cuda', @@ -93,10 +96,11 @@ async function compressVideo(inputFile: string, outputFile: string) { console.log(); // Новая строка в конце if (code === 0) { console.log(`✅ Completed: ${outputFile}`); + resolve(); } else { console.error(`❌ Failed with code ${code}`); + reject(); } - resolve(); }); ffmpeg.stderr.on('data', (data) => { @@ -109,13 +113,17 @@ async function compressVideo(inputFile: string, outputFile: string) { }); } -const files = await readdir('.'); -const mp4Files = files.filter(file => file.match(/^VID_.*\.mp4$/)); -const filesCount = mp4Files.length; +const files = (await readdir('.')).filter(name => { + return (!name.startsWith('HEVC') && ['mp4', 'mov'].includes(extname(name).toLowerCase().slice(1))) +}); +let filesCount = files.length; for (let i = 0; i < filesCount; i++){ - const file = mp4Files[i]; - const outputFile = `HEVC_${file.slice(4)}`; + const file = files[i]; + + // const outputFile = `HEVC_${file.slice(4)}`; + const outputFile = `HEVC_${file}`; console.log(`\nProcessing: ${file} [${i + 1}/${filesCount}]`); await compressVideo(file, outputFile); + // runInBackground('identity', [file, outputFile]) } diff --git a/bin/gpt.ts b/bin/gpt.ts new file mode 100755 index 0000000..f7d0456 --- /dev/null +++ b/bin/gpt.ts @@ -0,0 +1,29 @@ +#!/usr/bin/env node + +import { Ollama } from 'ollama'; +import {getStdin} from '../lib/ai-generated.ts'; + +const ollama = new Ollama({ host: 'http://127.0.0.1:11434' }); +const model = 'gemma3:12b'; +// const model = 'codellama:13b'; +// const model = 'aya:8b'; + + +async function streamChat() { + let [,,message] = process.argv; + if (!message) return; + const file = getStdin(); + const stream = await ollama.chat({ + model, + messages: [ + { role: 'user', content: `${message}\n${file}`}, + ], + stream: true, + }); + + for await (const chunk of stream) { + process.stdout.write(chunk.message.content); + } +} + +await streamChat(); diff --git a/bin/tutorial.ts b/bin/tutorial.ts new file mode 100644 index 0000000..7b231b4 --- /dev/null +++ b/bin/tutorial.ts @@ -0,0 +1,10 @@ +function sortingAlgorithm(x: number[]): number[] { + for (let i = 0; i < x.length; i++) { + for (let j = 0; j < x.length - 1; j++) { + if (x[j] > x[j + 1]) { + [x[j], x[j + 1]] = [x[j + 1], x[j]]; + } + } + } + return x; +} diff --git a/bun.lock b/bun.lock index 5ddc593..07f3dd5 100644 --- a/bun.lock +++ b/bun.lock @@ -4,6 +4,7 @@ "": { "dependencies": { "chalk": "^5.5.0", + "ollama": "^0.5.17", }, "devDependencies": { "@types/node": "^24.2.1", @@ -15,6 +16,10 @@ "chalk": ["chalk@5.5.0", "", {}, "sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg=="], + "ollama": ["ollama@0.5.17", "", { "dependencies": { "whatwg-fetch": "^3.6.20" } }, "sha512-q5LmPtk6GLFouS+3aURIVl+qcAOPC4+Msmx7uBb3pd+fxI55WnGjmLZ0yijI/CYy79x0QPGx3BwC3u5zv9fBvQ=="], + "undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], + + "whatwg-fetch": ["whatwg-fetch@3.6.20", "", {}, "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg=="], } } diff --git a/convert-1.ts b/convert-1.ts new file mode 100644 index 0000000..1a44224 --- /dev/null +++ b/convert-1.ts @@ -0,0 +1,28 @@ +import { readdir, stat } from 'fs/promises'; +import path from 'path'; +import { exec } from 'child_process'; + +const videoExtensions = ['mp4', 'avi', 'mov', 'mkv', 'flv', 'wmv', 'mpeg', 'mpg']; + +(async () => { + try { + const files = await readdir('.'); + for (const file of files) { + const stats = await stat(file); + if (!stats.isFile()) continue; + + const ext = path.extname(file).slice(1).toLowerCase(); + if (videoExtensions.includes(ext) && !file.startsWith('HEVC_')) { + const newFileName = 'HEVC_' + file; + const command = `ffmpeg -i "${file}" -c:v hevc_nvenc -preset slow -crf 23 -c:a aac "${newFileName}"`; + + exec(command, (err) => { + if (err) console.error(`Conversion failed for ${file}: ${err}`); + else console.log(`Converted ${file} → ${newFileName}`); + }); + } + } + } catch (err) { + console.error('Error processing files:', err); + } +})(); diff --git a/convert-2.ts b/convert-2.ts new file mode 100644 index 0000000..92579b1 --- /dev/null +++ b/convert-2.ts @@ -0,0 +1,58 @@ +import { exec } from 'child_process'; +import { readdir, stat } from 'fs'; +import path from 'path'; + +const currentDir = './'; // Текущая директория + +function isVideoFile(filePath: string): Promise { + return new Promise((resolve) => { + stat(filePath, (err, stats) => { + if (err) { + console.error(`Ошибка при получении информации о файле ${filePath}:`, err); + resolve(false); + return; + } + const ext = path.extname(filePath).toLowerCase(); + const isVideo = ['.mp4', '.mov', '.avi', '.mkv'].includes(ext); + resolve(isVideo && stats.size > 0); // Убеждаемся, что файл не пустой + }); + }); +} + +function compressVideoWithFFmpeg(filePath: string): void { + const outputFilePath = `HEVC_${path.basename(filePath)}`; + exec(`ffmpeg -i ${filePath} -c:v hevc_nvenc ${outputFilePath}`, (error, stdout, stderr) => { + if (error) { + console.error('Ошибка при сжатии видео:', error); + return; + } + if (stderr) { + console.error('FFmpeg ошибка:', stderr); + return; + } + console.log(`Сжата файл: ${filePath} в ${outputFilePath}`); + }); +} + +function walkThroughDirectory(dir: string): void { + readdir(dir, { withFileTypes: true }, (err, files) => { + if (err) { + console.error('Ошибка при чтении директории:', err); + return; + } + files.forEach((file) => { + const fullPath = path.join(dir, file.name); + if (file.isDirectory()) { + walkThroughDirectory(fullPath); // Рекурсивно обходим поддиректории + } else { + isVideoFile(fullPath).then((isVideo) => { + if (isVideo) { + compressVideoWithFFmpeg(fullPath); + } + }); + } + }); + }); +} + +walkThroughDirectory(currentDir); diff --git a/lib/ai-generated.ts b/lib/ai-generated.ts new file mode 100644 index 0000000..753a341 --- /dev/null +++ b/lib/ai-generated.ts @@ -0,0 +1,10 @@ +import {spawn} from 'child_process'; +import {readFileSync} from 'node:fs'; + +export function runInBackground(command: string, args?: string[]) { + const proc = spawn(command, args ?? [], {detached: true, stdio: 'ignore'}); + proc.unref(); + return proc.pid; +} + +export const getStdin = () => readFileSync(0, 'utf8'); diff --git a/package.json b/package.json index c57fec9..4edb3d4 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "@types/node": "^24.2.1" }, "dependencies": { - "chalk": "^5.5.0" + "chalk": "^5.5.0", + "ollama": "^0.5.17" } }