parent
fb75377969
commit
4cdd8c0d43
14 changed files with 2076 additions and 3 deletions
apps
configurations/nos/modules/comics/komga
justfilepackages
scopedPackages
|
@ -8,6 +8,7 @@ This directory contains every derivations for apps exposed by this flake.
|
||||||
| ---- | ----------- |
|
| ---- | ----------- |
|
||||||
| `extract-subs` | Extract all `srt` subtitle files from a `mkv` video with the appropriate name. |
|
| `extract-subs` | Extract all `srt` subtitle files from a `mkv` video with the appropriate name. |
|
||||||
| `gen-docs` | Generates the READMEs in this repository from nix attributes. |
|
| `gen-docs` | Generates the READMEs in this repository from nix attributes. |
|
||||||
|
| `list2series` | Converts a Komga read list into a comics series for reading with mihon. |
|
||||||
| `mc-mods` | Checks if a list of mods have a version available for a specific Minecraft version and a specific loader. |
|
| `mc-mods` | Checks if a list of mods have a version available for a specific Minecraft version and a specific loader. |
|
||||||
| `pin-inputs` | Takes a list of inputs to pin to their current rev in `flake.lock`. |
|
| `pin-inputs` | Takes a list of inputs to pin to their current rev in `flake.lock`. |
|
||||||
| `update-sources` | Updates all derivation sources in this repository and generates a commit message for the changes made. |
|
| `update-sources` | Updates all derivation sources in this repository and generates a commit message for the changes made. |
|
||||||
|
|
3
apps/list2series/.envrc
Normal file
3
apps/list2series/.envrc
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
use flake $FLAKE#node
|
||||||
|
(cd ../config; npm ci)
|
||||||
|
npm ci
|
1
apps/list2series/.gitignore
vendored
Normal file
1
apps/list2series/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.env
|
11
apps/list2series/default.nix
Normal file
11
apps/list2series/default.nix
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{buildApp, ...}:
|
||||||
|
buildApp {
|
||||||
|
src = ./.;
|
||||||
|
npmDepsHash = "sha256-GrGSXKAH8w068rIOFwmQoM1Zn68ESkazBiDaoE0mrQw=";
|
||||||
|
|
||||||
|
runtimeInputs = [];
|
||||||
|
|
||||||
|
meta.description = ''
|
||||||
|
Converts a Komga read list into a comics series for reading with mihon.
|
||||||
|
'';
|
||||||
|
}
|
3
apps/list2series/eslint.config.ts
Normal file
3
apps/list2series/eslint.config.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import eslintConf from 'eslint-conf';
|
||||||
|
|
||||||
|
export default eslintConf;
|
1812
apps/list2series/package-lock.json
generated
Normal file
1812
apps/list2series/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
21
apps/list2series/package.json
Normal file
21
apps/list2series/package.json
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "list2series",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"bin": "out/bin/app.cjs",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"build": "node_ver=$(node -v); esbuild src/app.ts --bundle --platform=node --target=\"node${node_ver:1:2}\" --outfile=out/bin/app.cjs"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "22.13.11",
|
||||||
|
"axios": "^1.8.4",
|
||||||
|
"esbuild": "0.25.1",
|
||||||
|
"eslint": "9.23.0",
|
||||||
|
"jiti": "2.4.2",
|
||||||
|
"pkg-types": "2.1.0",
|
||||||
|
"typescript": "5.8.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"eslint-conf": "file:../config"
|
||||||
|
}
|
||||||
|
}
|
204
apps/list2series/src/app.ts
Normal file
204
apps/list2series/src/app.ts
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
import axios from 'axios';
|
||||||
|
import { copyFileSync, mkdirSync, readFileSync, rmSync } from 'fs';
|
||||||
|
import { basename } from 'path';
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
type Book = any;
|
||||||
|
|
||||||
|
const API = JSON.parse(
|
||||||
|
readFileSync(`${process.env.FLAKE}/apps/list2series/.env`, { encoding: 'utf-8' }),
|
||||||
|
).API;
|
||||||
|
|
||||||
|
// Examples of calling this script:
|
||||||
|
// $ just l2s copy 0K65Q482KK7SD
|
||||||
|
// $ just l2s meta 0K65Q482KK7SD
|
||||||
|
const LIST_ID = process.argv[3];
|
||||||
|
|
||||||
|
const getListInfo = async() => {
|
||||||
|
const res = await axios.request({
|
||||||
|
method: 'get',
|
||||||
|
maxBodyLength: Infinity,
|
||||||
|
url: `https://komga.nelim.org/api/v1/readlists/${LIST_ID}`,
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'X-API-Key': API,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSeriesBooks = async(listName: string, seriesPath: string): Promise<Book[]> => {
|
||||||
|
const series = await axios.request({
|
||||||
|
method: 'post',
|
||||||
|
maxBodyLength: Infinity,
|
||||||
|
url: 'https://komga.nelim.org/api/v1/series/list?unpaged=true',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'X-API-Key': API,
|
||||||
|
},
|
||||||
|
data: JSON.stringify({
|
||||||
|
condition: {
|
||||||
|
title: {
|
||||||
|
operator: 'isNot',
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const seriesId = (series.data.content as Book[]).find((s) => s.url === seriesPath).id;
|
||||||
|
|
||||||
|
// Reset Series metadata
|
||||||
|
axios.request({
|
||||||
|
method: 'patch',
|
||||||
|
maxBodyLength: Infinity,
|
||||||
|
url: `https://komga.nelim.org/api/v1/series/${seriesId}/metadata`,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-API-Key': API,
|
||||||
|
},
|
||||||
|
data: JSON.stringify({
|
||||||
|
ageRating: null,
|
||||||
|
ageRatingLock: true,
|
||||||
|
alternateTitles: null,
|
||||||
|
alternateTitlesLock: true,
|
||||||
|
genres: null,
|
||||||
|
genresLock: true,
|
||||||
|
language: null,
|
||||||
|
languageLock: true,
|
||||||
|
links: null,
|
||||||
|
linksLock: true,
|
||||||
|
publisherLock: true,
|
||||||
|
readingDirection: 'LEFT_TO_RIGHT',
|
||||||
|
readingDirectionLock: true,
|
||||||
|
sharingLabels: null,
|
||||||
|
sharingLabelsLock: true,
|
||||||
|
status: null,
|
||||||
|
statusLock: true,
|
||||||
|
summary: null,
|
||||||
|
summaryLock: true,
|
||||||
|
tags: null,
|
||||||
|
tagsLock: true,
|
||||||
|
title: listName,
|
||||||
|
titleLock: true,
|
||||||
|
titleSort: listName,
|
||||||
|
titleSortLock: true,
|
||||||
|
totalBookCountLock: true,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const books = await axios.request({
|
||||||
|
method: 'post',
|
||||||
|
maxBodyLength: Infinity,
|
||||||
|
url: 'https://komga.nelim.org/api/v1/books/list?unpaged=true',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'X-API-Key': API,
|
||||||
|
},
|
||||||
|
data: JSON.stringify({
|
||||||
|
condition: {
|
||||||
|
seriesId: {
|
||||||
|
operator: 'is',
|
||||||
|
value: seriesId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
return books.data.content;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getBookInfo = async(id: string) => {
|
||||||
|
const res = await axios.request({
|
||||||
|
method: 'get',
|
||||||
|
maxBodyLength: Infinity,
|
||||||
|
url: `https://komga.nelim.org/api/v1/books/${id}`,
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'X-API-Key': API,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const scanLibrary = async() => {
|
||||||
|
return await axios.request({
|
||||||
|
method: 'post',
|
||||||
|
maxBodyLength: Infinity,
|
||||||
|
url: 'https://komga.nelim.org/api/v1/libraries/0K4QG58XA29DZ/scan',
|
||||||
|
headers: {
|
||||||
|
'X-API-Key': API,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setBookMetadata = async(i: number, source: Book, target: Book) => {
|
||||||
|
source.metadata.title = `${source.seriesTitle} Issue #${source.number}`;
|
||||||
|
source.metadata.number = i.toString();
|
||||||
|
source.metadata.numberSort = i;
|
||||||
|
|
||||||
|
const metadata = JSON.stringify(source.metadata);
|
||||||
|
|
||||||
|
const res = await axios.request({
|
||||||
|
method: 'patch',
|
||||||
|
maxBodyLength: Infinity,
|
||||||
|
url: `https://komga.nelim.org/api/v1/books/${target.id}/metadata`,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-API-Key': API,
|
||||||
|
},
|
||||||
|
data: metadata,
|
||||||
|
});
|
||||||
|
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
const main = async() => {
|
||||||
|
const list = await getListInfo();
|
||||||
|
const ids = list.bookIds as string[];
|
||||||
|
const seriesPath = `/data/comics/[List] ${list.name}`;
|
||||||
|
|
||||||
|
const listBooks = [] as Book[];
|
||||||
|
|
||||||
|
for (let i = 0; i < ids.length; i++) {
|
||||||
|
const book = await getBookInfo(ids[i]);
|
||||||
|
|
||||||
|
listBooks[i] = book;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (process.argv[2] === 'copy') {
|
||||||
|
rmSync(seriesPath, { recursive: true, force: true });
|
||||||
|
mkdirSync(seriesPath, { recursive: true });
|
||||||
|
|
||||||
|
for (const book of listBooks) {
|
||||||
|
const bookPath = book.url;
|
||||||
|
const inListPath = `${seriesPath}/${basename(bookPath)}`;
|
||||||
|
|
||||||
|
console.log(`copying ${basename(bookPath)}`);
|
||||||
|
copyFileSync(bookPath, inListPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
await scanLibrary();
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (process.argv[2] === 'meta') {
|
||||||
|
const seriesBooks = await getSeriesBooks(`[List] ${list.name}`, seriesPath);
|
||||||
|
|
||||||
|
for (const target of seriesBooks) {
|
||||||
|
const source = listBooks.find((b) => basename(b.url) === basename(target.url));
|
||||||
|
|
||||||
|
if (source) {
|
||||||
|
const i = listBooks.indexOf(source) + 1;
|
||||||
|
|
||||||
|
console.log(`Setting metadata for ${source.name}`);
|
||||||
|
setBookMetadata(i, source, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
main();
|
10
apps/list2series/tsconfig.json
Normal file
10
apps/list2series/tsconfig.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
|
"extends": "../config/tsconfig.base.json",
|
||||||
|
"includes": [
|
||||||
|
"*.ts",
|
||||||
|
"**/*.ts",
|
||||||
|
"*.js",
|
||||||
|
"**/*.js"
|
||||||
|
]
|
||||||
|
}
|
|
@ -8,6 +8,7 @@
|
||||||
listToAttrs (map (x: nameValuePair x (callPackage ./${x})) [
|
listToAttrs (map (x: nameValuePair x (callPackage ./${x})) [
|
||||||
"extract-subs"
|
"extract-subs"
|
||||||
"gen-docs"
|
"gen-docs"
|
||||||
|
"list2series"
|
||||||
"mc-mods"
|
"mc-mods"
|
||||||
"pin-inputs"
|
"pin-inputs"
|
||||||
"update-sources"
|
"update-sources"
|
||||||
|
|
|
@ -30,7 +30,9 @@ in {
|
||||||
baseUri = "https://komga.nelim.org";
|
baseUri = "https://komga.nelim.org";
|
||||||
metadataUpdate.default = {
|
metadataUpdate.default = {
|
||||||
libraryType = "COMIC";
|
libraryType = "COMIC";
|
||||||
overrideExistingCovers = false;
|
bookCovers = true;
|
||||||
|
seriesCovers = true;
|
||||||
|
overrideExistingCovers = true;
|
||||||
overrideComicInfo = true;
|
overrideComicInfo = true;
|
||||||
postProcessing = {
|
postProcessing = {
|
||||||
seriesTitle = true;
|
seriesTitle = true;
|
||||||
|
|
4
justfile
4
justfile
|
@ -15,6 +15,10 @@ genflake:
|
||||||
|
|
||||||
alejandra -q "$FLAKE"/flake.nix
|
alejandra -q "$FLAKE"/flake.nix
|
||||||
|
|
||||||
|
[positional-arguments]
|
||||||
|
l2s action list:
|
||||||
|
nix run "$FLAKE"#list2series -- "$@"
|
||||||
|
|
||||||
[positional-arguments]
|
[positional-arguments]
|
||||||
mc-mods version action='check':
|
mc-mods version action='check':
|
||||||
nix run "$FLAKE"#mc-mods -- "$@"
|
nix run "$FLAKE"#mc-mods -- "$@"
|
||||||
|
|
|
@ -12,7 +12,8 @@ This directory contains every derivations for packages exposed by this flake.
|
||||||
| `gsr-kms-server` | Small program giving safe KMS access to gpu-screen-recorder when recording a monitor. This is the only part of gpu-screen-recorder that could require root permissions. | https://git.dec05eba.com/gpu-screen-recorder/about |
|
| `gsr-kms-server` | Small program giving safe KMS access to gpu-screen-recorder when recording a monitor. This is the only part of gpu-screen-recorder that could require root permissions. | https://git.dec05eba.com/gpu-screen-recorder/about |
|
||||||
| `homepage` | Highly customisable dashboard with Docker and service API integrations. | https://gethomepage.dev |
|
| `homepage` | Highly customisable dashboard with Docker and service API integrations. | https://gethomepage.dev |
|
||||||
| `jmusicbot` | Discord music bot that's easy to set up and run yourself | https://github.com/jagrosh/MusicBot |
|
| `jmusicbot` | Discord music bot that's easy to set up and run yourself | https://github.com/jagrosh/MusicBot |
|
||||||
| `komf` | komf is a tool that fetches metadata and thumbnails for your digital comic book library. | https://github.com/Snd-R/komf |
|
| `kapowarr` | Kapowarr is a software to build and manage a comic book library, fitting in the \*arr suite of software | https://casvt.github.io/Kapowarr |
|
||||||
|
| `komf` | Komf is a tool that fetches metadata and thumbnails for your digital comic book library. | https://github.com/Snd-R/komf |
|
||||||
| `libratbag` | Configuration library for gaming mice | https://github.com/libratbag/libratbag |
|
| `libratbag` | Configuration library for gaming mice | https://github.com/libratbag/libratbag |
|
||||||
| `librespot-auth` | A simple program for populating a credentials.json via Spotify's zeroconf authentication. | https://github.com/dspearson/librespot-auth |
|
| `librespot-auth` | A simple program for populating a credentials.json via Spotify's zeroconf authentication. | https://github.com/dspearson/librespot-auth |
|
||||||
| `nbted` | Command-line NBT editor written in Rust. It does precisely one thing: convert NBT files to a pretty text format, and reverse the pretty text format back into NBT. | https://github.com/C4K3/nbted |
|
| `nbted` | Command-line NBT editor written in Rust. It does precisely one thing: convert NBT files to a pretty text format, and reverse the pretty text format back into NBT. | https://github.com/C4K3/nbted |
|
||||||
|
|
|
@ -27,7 +27,6 @@ Every extensions I use in my firefox module.
|
||||||
| `bitwarden` | At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information. | https://bitwarden.com |
|
| `bitwarden` | At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information. | https://bitwarden.com |
|
||||||
| `darkreader` | Dark mode for every website. Take care of your eyes, use dark theme for night and daily browsing. | https://darkreader.org/ |
|
| `darkreader` | Dark mode for every website. Take care of your eyes, use dark theme for night and daily browsing. | https://darkreader.org/ |
|
||||||
| `floccus` | Sync your bookmarks and tabs across browsers via Nextcloud, any WebDAV service, any Git service, via a local file, via Google Drive. | https://floccus.org |
|
| `floccus` | Sync your bookmarks and tabs across browsers via Nextcloud, any WebDAV service, any Git service, via a local file, via Google Drive. | https://floccus.org |
|
||||||
| `frankerfacez` | The Twitch Enhancement Suite - Get custom emotes and tons of new features you'll never want to go without. | https://www.frankerfacez.com |
|
|
||||||
| `google-container` | THIS IS NOT AN OFFICIAL ADDON FROM MOZILLA! It is a fork of the Facebook Container addon. Prevent Google from tracking you around the web. The Google Container extension helps you take control and isolate your web activity from Google. | https://github.com/containers-everywhere/contain-google |
|
| `google-container` | THIS IS NOT AN OFFICIAL ADDON FROM MOZILLA! It is a fork of the Facebook Container addon. Prevent Google from tracking you around the web. The Google Container extension helps you take control and isolate your web activity from Google. | https://github.com/containers-everywhere/contain-google |
|
||||||
| `image-search-options` | A customizable reverse image search tool that conveniently presents a variety of top image search engines. | http://saucenao.com/ |
|
| `image-search-options` | A customizable reverse image search tool that conveniently presents a variety of top image search engines. | http://saucenao.com/ |
|
||||||
| `istilldontcareaboutcookies` | Community version of the popular extension "I don't care about cookies" https://github.com/OhMyGuus/I-Dont-Care-About-Cookies | https://github.com/OhMyGuus/I-Dont-Care-About-Cookies |
|
| `istilldontcareaboutcookies` | Community version of the popular extension "I don't care about cookies" https://github.com/OhMyGuus/I-Dont-Care-About-Cookies | https://github.com/OhMyGuus/I-Dont-Care-About-Cookies |
|
||||||
|
|
Loading…
Add table
Reference in a new issue