-
-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Video quality selection #5
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,12 +10,14 @@ import bot from '@/helpers/bot' | |
import cleanupDownloadJobs from '@/helpers/cleanupDownloadJobs' | ||
import configureI18n from '@/middlewares/configureI18n' | ||
import handleAudio from '@/handlers/handleAudio' | ||
import handleMaxQuality from '@/handlers/handleMaxQuality' | ||
import handleUrl from '@/handlers/handleUrl' | ||
import i18n from '@/helpers/i18n' | ||
import ignoreOldMessageUpdates from '@/middlewares/ignoreOldMessageUpdates' | ||
import report from '@/helpers/report' | ||
import sendHelp from '@/handlers/sendHelp' | ||
import startMongo from '@/helpers/startMongo' | ||
import { resolutionMenu } from './menus/resolutionMenu' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Не используй относительные импорты, только |
||
|
||
async function runApp() { | ||
console.log('Starting app...') | ||
|
@@ -33,6 +35,9 @@ async function runApp() { | |
bot.command(['help', 'start'], sendHelp) | ||
bot.command('language', sendLanguage) | ||
bot.command('audio', handleAudio) | ||
bot.command('max_quality', handleMaxQuality) | ||
// Menus | ||
bot.use(resolutionMenu) | ||
// Handlers | ||
bot.hears( | ||
/[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)?/i, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import Context from '@/models/Context' | ||
|
||
export default async function handleMaxQuality(ctx: Context) { | ||
ctx.dbchat.autoMaxQuality = !ctx.dbchat.autoMaxQuality | ||
await ctx.dbchat.save() | ||
return ctx.reply( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use |
||
ctx.i18n.t( | ||
ctx.dbchat.autoMaxQuality ? 'max_quality_on' : 'max_quality_off' | ||
), | ||
{ | ||
reply_to_message_id: ctx.message?.message_id, | ||
} | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,11 @@ | ||
import Context from '@/models/Context' | ||
import createDownloadJobAndRequest from '@/helpers/createDownloadJobAndRequest' | ||
import report from '@/helpers/report' | ||
import { resolutionMenu } from '@/menus/resolutionMenu' | ||
import bot from '@/helpers/bot' | ||
import { findOrCreateShortUrl } from '@/models/ShortUrl' | ||
|
||
export default function handleUrl(ctx: Context) { | ||
export default async function handleUrl(ctx: Context) { | ||
try { | ||
const match = ctx.message?.text?.match( | ||
/[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)?/i | ||
|
@@ -12,8 +15,22 @@ export default function handleUrl(ctx: Context) { | |
reply_to_message_id: ctx.message?.message_id, | ||
}) | ||
} | ||
|
||
const url = match[0] | ||
return createDownloadJobAndRequest(ctx, url) | ||
|
||
if (ctx.dbchat.autoMaxQuality) { | ||
return createDownloadJobAndRequest(ctx, url) | ||
} else { | ||
const waitMessage = await ctx.reply(ctx.i18n.t('check_resolutions')) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use replyWithLocalization |
||
const shortUrl = await findOrCreateShortUrl(url) | ||
bot.api.deleteMessage(waitMessage.chat.id, waitMessage.message_id) | ||
|
||
ctx.shortUrlId = shortUrl.shortId | ||
return ctx.reply(ctx.i18n.t('resolutions_question'), { | ||
reply_markup: resolutionMenu, | ||
reply_to_message_id: ctx.message?.message_id, | ||
}) | ||
} | ||
} catch (error) { | ||
report(error, { ctx, location: 'handleUrl' }) | ||
return ctx.reply(ctx.i18n.t('error_cannot_start_download'), { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import report from './report' | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
const youtubedl = require('@borodutch-labs/yt-dlp-exec') | ||
|
||
export default async function checkAvailableResolutions(url: string) { | ||
try { | ||
const json = await youtubedl(url, { dumpJson: true }) | ||
|
||
return Array.from( | ||
new Set<number>( | ||
json.formats | ||
.map((f: any) => f.height) | ||
.filter((height: any) => height >= 144) | ||
) | ||
) | ||
} catch (error) { | ||
report(error, { location: 'checkResolutions', meta: url }) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import createDownloadJobAndRequest from '@/helpers/createDownloadJobAndRequest' | ||
import Context from '@/models/Context' | ||
import { findShortUrl } from '@/models/ShortUrl' | ||
import { Menu } from '@grammyjs/menu' | ||
|
||
export const resolutionMenu = new Menu<Context>('resolution-menu').dynamic( | ||
async (ctx, range) => { | ||
const shortUrl = await findShortUrl( | ||
ctx.shortUrlId || ctx.match?.toString()! | ||
) | ||
|
||
if (!shortUrl) { | ||
ctx.reply(ctx.i18n.t('error_outdated_menu')) | ||
return | ||
} | ||
|
||
for (const resolution of shortUrl.availableResolutions) { | ||
range | ||
.text({ text: `${resolution}p`, payload: shortUrl.shortId }, (ctx) => { | ||
createDownloadJobAndRequest(ctx, shortUrl.url, resolution) | ||
return ctx.deleteMessage() | ||
}) | ||
.row() | ||
} | ||
range.text({ text: `Cancel`, payload: shortUrl.shortId }, (ctx) => | ||
ctx.deleteMessage() | ||
) | ||
} | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { FindOrCreate } from '@typegoose/typegoose/lib/defaultClasses' | ||
import { getModelForClass, prop } from '@typegoose/typegoose' | ||
import randomToken = require('random-token') | ||
import checkAvailableResolutions from '@/helpers/checkAvailableResolutions' | ||
|
||
export class ShortUrl extends FindOrCreate { | ||
@prop({ | ||
required: true, | ||
index: true, | ||
unique: true, | ||
default: () => randomToken(16), | ||
}) | ||
shortId!: string | ||
@prop({ required: true }) | ||
url!: string | ||
@prop({ required: true, type: () => [Number] }) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Можно обойтись без этого поля? |
||
availableResolutions!: number[] | ||
} | ||
|
||
const ShortUrlModel = getModelForClass(ShortUrl, { | ||
schemaOptions: { timestamps: true }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Давай использовать |
||
}) | ||
|
||
export async function findOrCreateShortUrl(url: string) { | ||
const shortUrl = await ShortUrlModel.findOne({ url }) | ||
if (shortUrl) { | ||
return shortUrl | ||
} | ||
|
||
const availableResolutions = await checkAvailableResolutions(url) | ||
|
||
return new ShortUrlModel({ url, availableResolutions }).save() | ||
} | ||
|
||
export async function findShortUrl(shortId: string) { | ||
return ShortUrlModel.findOne({ shortId }) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
declare module 'random-token' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Нам это точно нужно? Мы же делаем |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Вместо этого, давай сделаем
/chooseResolution
, который по дефолтуfalse