-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
135 lines (113 loc) 路 3.72 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import { mkdir, readdir, rename } from 'node:fs/promises'
import path from 'node:path'
import chalk from 'chalk'
import groupBy from 'lodash.groupby'
import { get as imdbGet } from 'imdb-api'
import inquirer from 'inquirer'
import ora from 'ora'
import parseVideoName from 'video-name-parser'
const renameFiles = configs =>
configs.map(async ({ sourceName, sourcePath, targetName, targetPath }) => {
const oldPath = path.join(sourcePath, sourceName)
const newPath = path.join(targetPath, targetName)
await mkdir(path.dirname(newPath), { recursive: true })
await rename(oldPath, newPath)
})
export default async (source, options = {}) => {
const { apiKey = process.env.OMDB_API_KEY, force, output, tree } = options
const sourcePath = path.resolve(source)
const targetPath = output ? path.resolve(output) : sourcePath
if (apiKey == null) {
console.error(
chalk.red(
[
'No API key found.',
'Please specify a valid OMDb API key with the `--api-key` option or `OMDB_API_KEY` environment variable.',
`You can get one at ${chalk.blue.underline(
'https://www.omdbapi.com/apikey.aspx',
)}. See \`--help\` for more information.`,
].join('\n'),
),
)
return process.exit(1)
}
const spinner = ora('Reading files').start()
const filenames = await readdir(sourcePath)
const metadataMap = groupBy(
filenames
.map(filename => ({
...parseVideoName(filename),
filename,
extension: path.extname(filename),
}))
.filter(({ type }) => type === 'series'),
'name',
)
spinner.text = 'Fetching data'
const promises = Object.keys(metadataMap).map(async name => {
let tvShow, episodes
try {
tvShow = await imdbGet({ name }, { apiKey })
episodes = await tvShow.episodes()
} catch (err) {
return
}
const episodeMap = groupBy(episodes, 'season')
const configs = metadataMap[name]
.map(metadata => {
const season = episodeMap[metadata.season] || []
const episodes = season
.filter(({ episode }) => metadata.episode.includes(episode))
.sort((a, b) => a.episode - b.episode)
if (episodes.length !== metadata.episode.length) return undefined
const episode = episodes.map(({ episode }) => episode).join('-')
const name = episodes.map(({ name }) => name).join(' | ')
const sourceName = metadata.filename
const targetName = path.join(
tree
? `${tvShow.name} (${tvShow.start_year})/Season ${metadata.season}`
: '',
`${episode}. ${name}${metadata.extension}`,
)
return {
sourceName,
sourcePath,
targetName,
targetPath,
}
})
.filter(Boolean)
return { configs, tvShow }
})
const results = (await Promise.all(promises)).filter(Boolean)
spinner.stop()
for (const result of results) {
const { configs, tvShow } = result
const changes = configs.reduce(
(acc, { sourceName, sourcePath, targetName, targetPath }) =>
`${acc}\t${chalk.green(
`${sourceName} -> ${path.relative(
sourcePath,
path.join(targetPath, targetName),
)}`,
)}\n`,
`\n${chalk.bold(
`${tvShow.name} (${tvShow.start_year})`,
)}\n${chalk.blue.underline(tvShow.imdburl)}\n\n`,
)
let confirmed = false
if (!force) {
console.log(changes)
const { rename } = await inquirer.prompt({
type: 'confirm',
name: 'rename',
message: 'Rename files?',
default: true,
})
confirmed = rename
}
if (force || confirmed) {
await Promise.all(renameFiles(configs))
}
}
}