Skip to content

Instantly share code, notes, and snippets.

@scooterpsu
Last active September 27, 2023 13:16
Show Gist options
  • Save scooterpsu/9a91da3cfebe2b4754876123c198acef to your computer and use it in GitHub Desktop.
Save scooterpsu/9a91da3cfebe2b4754876123c198acef to your computer and use it in GitHub Desktop.
Komga to Chunky Interface
This is a thing I made to get (originally) Komga reading lists into Chunky on my iPad.
This can now send single issues, whole series, reading lists, or selected loose files.
Requirements:
Jailbroken iPad
Tweaks from Cydia (or other tweak source) - Open, cURL, Activator
Chunky Reader
Linux binaries/support - bc, ssh, jq, websocketd (https://github.com/joewalnes/websocketd)
Instructions:
Put websocketd binary with .sh files and autorun, edit for your use-case, chmod +x all the things, run autorun.
Edit komga.user.js for your use-case, install with Tampermonkey (might work with Firemonkey, unsure), profit.
#!/bin/bash
cd $(dirname "$0")
./websocketd --port=9000 ./runme.sh
// ==UserScript==
// @name Send to iPad Button
// @namespace http://tampermonkey.net/
// @version 1.1
// @description websocketd buttons for Komga
// @author scooterpsu
// @include http://192.168.1.110:8099/*
// @grant none
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @require https://gist.github.com/raw/2625891/waitForKeyElements.js
// @require https://code.jquery.com/ui/1.11.4/jquery-ui.min.js
// ==/UserScript==
/* globals $, waitForKeyElements */
var websocket = "ws://192.168.1.110:9000/?type=";
var ipadButton = $('<div class="col col-auto"><a class="tmelement v-btn v-btn--is-elevated v-btn--has-bg v-size--small" id="ipadButton" target="_blank"><span class="v-btn__content"><i aria-hidden="true" class="v-icon notranslate v-icon--left mdi mdi-tablet-android" style="font-size: 16px"></i> Send To iPad </span></a></div>');
var overlay = $('<div class="tmelement container v-toolbar v-sheet" id="logContainer" style="position:fixed; z-index: 10; margin: auto; left:0; right: 0; top: 0; bottom:0; width:60%; height:60%;padding:0;min-height:415px;"><header class="v-sheet v-toolbar base"><div class="v-toolbar__content"><span style="flex-grow:0; margin-right:14px;" class="v-btn__content"><i aria-hidden="true" class="v-icon notranslate mdi mdi-tablet-android"></i></span><div class="v-toolbar__title"><span>Sending to iPad</span></div><span id="counter" class="tmelement mx-4 v-chip v-chip--label v-chip--no-color v-size--default" style="display:none;"><span id="counterText" class="v-chip__content"><span style="font-size: 1.1rem;"></span></span></span><div class="spacer"></div><button type="button" class="v-btn v-btn--icon v-btn--round v-size--default tmelement" onclick="$(\'#log\').empty();$(\'#logContainer\').remove();"><span class="v-btn__content"><i aria-hidden="true" class="v-icon notranslate mdi mdi-close"></i><span class="v-tooltip v-tooltip--bottom"></span></span></button></div></header><div style="width:100%; height:5px;background-color: var(--v-secondary-base);opacity:0.3;"></div><div id="progressbar" style="width: 100%;height:5px;margin-top:-5px;"></div><div class="row" style="margin: 0;"><div class="col-auto"><div class="tmelement v-card v-image v-responsive" style="width: 195px;"><div class="v-responsive__sizer" style="padding-bottom: 260px;"></div><div id="thumbnail" class="v-image__image v-image__image--contain" style="background-position: center center;"></div></div><div class="iosstats" style="width: 195px;margin-top: 15px;display:none;"><hr role="separator" aria-orientation="horizontal" class="v-divider tmelement" style="margin-bottom: 8px;"><span style="float: left;" class="v-btn__content"><i aria-hidden="true" class="v-icon notranslate mdi mdi-folder-information tmelement" style="font-size: 30px;margin-left:5px;margin-top:2px;"></i></span><div style="float: right;" class="body-2" id="capacity"></div><div style="float: right;"class="body-2" id="freespace"></div></div></div><div class="col" style="padding:0;max-width: calc(100% - 219px);"><pre style="overflow-y:auto;overflow-x:hidden; height:calc(60vh - 63px); padding:10px;" class="body-2" id="log"></pre></div></div></div>');
var toolbarButton=$('<button type="button" id="toolbarButton" class="tmelement v-btn v-btn--icon v-btn--round v-size--default"><span class="v-btn__content"><i aria-hidden="true" class="tmelement v-icon notranslate mdi mdi-tablet-android"></i><span class="v-tooltip v-tooltip--bottom"></span></span></button>');
var toolTip = $('<div id="toolTip" class="v-tooltip__content" style="z-index: 8; display: none; opacity: 1;"><span>Send to iPad</span></div>');
function addReadlistButton () {
if(!$('#ipadButton').length){
var type = "readlists";
var $downloadButton = $('a[title|="Download read list"]');
var id = $downloadButton[0].href.split('/file')[0].split('/').pop();
$downloadButton.parent().addClass('col-auto');
$downloadButton.parent().parent().append(ipadButton);
$('#ipadButton').attr('title','Send read list to iPad');
themeButton();
observer.observe($downloadButton[0], {
attributes: true,
attributeFilter: ['class']
});
$("#ipadButton").off("click");
$('#ipadButton').on('click', function() {
$("#logContainer").remove();
var ws = new WebSocket(websocket+type+"&id="+id);
ws.onopen = function() {
overlay.prependTo('.container:first');
$("#counter").hide();
$("#counterText").empty();
themeButton();
$('#thumbnail').css('background-image', 'url('+location.protocol+'//'+location.host+'/api/v1/readlists/'+id+'/thumbnail)');
$('#progressbar').progressbar({value:0});
$('.ui-progressbar-value').css('height', '100%').css('background','var(--v-secondary-base)');
};
ws.onclose = function() {
setTimeout(function(){
$('#log').empty();
$('#logContainer').remove();
}, 5000);
};
ws.onmessage = function(event) {
if (event.data.startsWith("BOOKID:")){
$('#thumbnail').css('background-image', 'url('+location.protocol+'//'+location.host+'/api/v1/books/'+event.data.split("BOOKID:")[1]+'/thumbnail)');
}else if (event.data.startsWith("PROGRESS:")){
$('#progressbar').progressbar({value:parseFloat(event.data.split("PROGRESS:")[1])});
}else if (event.data.startsWith("COUNTER:")){
$('#counter').show();
$('#counter > span').text(event.data.split("COUNTER:")[1]);
}else if (event.data.startsWith("FREESPACE:")){
$('.iosstats').show();
$('#freespace').text(event.data.split("FREESPACE:")[1]);
}else if (event.data.startsWith("TOTALSPACE:")){
$('.iosstats').show();
$('#capacity').text(event.data.split("TOTALSPACE:")[1]);
}else{
log(event.data);
}
};
});
}
}
waitForKeyElements ("a[title|='Download read list']", addReadlistButton);
function addSeriesButton () {
if(!$('#ipadButton').length){
var type = "series";
var $downloadButton = $('a[title|="Download series"]');
var id = $downloadButton[0].href.split('/file')[0].split('/').pop();
$downloadButton.parent().parent().append(ipadButton);
$('#ipadButton').attr('title','Send series to iPad');
themeButton();
observer.observe($downloadButton[0], {
attributes: true,
attributeFilter: ['class']
});
$("#ipadButton").off("click");
$('#ipadButton').on('click', function() {
$("#logContainer").remove();
var ws = new WebSocket(websocket+type+"&id="+id);
ws.onopen = function() {
overlay.prependTo('.container:first');
$("#counter").hide();
$("#counterText").empty();
themeButton();
$('#thumbnail').css('background-image', 'url('+location.protocol+'//'+location.host+'/api/v1/series/'+id+'/thumbnail)');
$('#progressbar').progressbar({value:0});
$('.ui-progressbar-value').css('height', '100%').css('background','var(--v-secondary-base)');
};
ws.onclose = function() {
setTimeout(function(){
$('#log').empty();
$('#logContainer').remove();
}, 5000);
};
ws.onmessage = function(event) {
if (event.data.startsWith("BOOKID:")){
$('#thumbnail').css('background-image', 'url('+location.protocol+'//'+location.host+'/api/v1/books/'+event.data.split("BOOKID:")[1]+'/thumbnail)');
}else if (event.data.startsWith("PROGRESS:")){
$('#progressbar').progressbar({value:parseFloat(event.data.split("PROGRESS:")[1])});
}else if (event.data.startsWith("COUNTER:")){
$('#counter').show();
$('#counter > span').text(event.data.split("COUNTER:")[1]);
}else if (event.data.startsWith("FREESPACE:")){
$('.iosstats').show();
$('#freespace').text(event.data.split("FREESPACE:")[1]);
}else if (event.data.startsWith("TOTALSPACE:")){
$('.iosstats').show();
$('#capacity').text(event.data.split("TOTALSPACE:")[1]);
}else{
log(event.data);
}
};
});
}
}
waitForKeyElements ("a[title|='Download series']", addSeriesButton);
function addFileButton () {
if(!$('#ipadButton').length){
var type = "books";
var $downloadButton = $('a[title|="Download file"]');
var id = $downloadButton[0].href.split('/file')[0].split('/').pop();
$downloadButton.parent().parent().append(ipadButton);
$('#ipadButton').attr('title','Send file to iPad');
themeButton();
observer.observe($downloadButton[0], {
attributes: true,
attributeFilter: ['class']
});
$("#ipadButton").off("click");
$('#ipadButton').on('click', function() {
$("#logContainer").remove();
var ws = new WebSocket(websocket+type+"&id="+id);
ws.onopen = function() {
overlay.prependTo('.container:first');
$("#counter").hide();
$("#counterText").empty();
themeButton();
$('#thumbnail').css('background-image', 'url('+location.protocol+'//'+location.host+'/api/v1/books/'+id+'/thumbnail)');
$('#progressbar').progressbar({value:0});
$('.ui-progressbar-value').css('height', '100%').css('background','var(--v-secondary-base)');
};
ws.onclose = function() {
setTimeout(function(){
$('#log').empty();
$('#logContainer').remove();
}, 5000);
};
ws.onmessage = function(event) {
if (event.data.startsWith("BOOKID:")){
$('#thumbnail').css('background-image', 'url('+location.protocol+'//'+location.host+'/api/v1/books/'+event.data.split("BOOKID:")[1]+'/thumbnail)');
}else if (event.data.startsWith("PROGRESS:")){
$('#progressbar').progressbar({value:parseFloat(event.data.split("PROGRESS:")[1])});
}else if (event.data.startsWith("COUNTER:")){
$('#counter').show();
$('#counter > span').text(event.data.split("COUNTER:")[1]);
}else if (event.data.startsWith("FREESPACE:")){
$('.iosstats').show();
$('#freespace').text(event.data.split("FREESPACE:")[1]);
}else if (event.data.startsWith("TOTALSPACE:")){
$('.iosstats').show();
$('#capacity').text(event.data.split("TOTALSPACE:")[1]);
}else{
log(event.data);
}
};
});
}
}
waitForKeyElements ("a[title|='Download file']", addFileButton);
function addToolbarButton () {
if(!$('#toolbarButton').length){
$('.v-toolbar__content > .spacer').after(toolbarButton);
themeButton();
var $closeButton = $('.sticky-bar .mdi-close');
observer.observe($closeButton[0], {
attributes: true,
attributeFilter: ['class']
});
$("#toolbarButton").off("click");
$("#toolbarButton").hover(
function() {
if($('#toolTip').length === 0){
$('.v-application--wrap').after(toolTip);
}
var leftOffset=$('#toolbarButton').offset().left+24-55;
var topOffset=$('#toolbarButton').offset().top+46;
$('#toolTip').css('left',leftOffset+"px").css('top',topOffset+"px");
$('#toolTip').fadeIn();
}, function() {
$('#toolTip').fadeOut();
}
);
var type;
$('#toolbarButton').on('click', function() {
var idArray = [];
var id = "";
var $borderedCells = $('.item-border').parent().parent().find('.v-image__image').not('.v-image__image--preload');
if( $borderedCells.length !== 1){
$borderedCells.each(function(){
var bookID = $(this).css('background-image').split('/thumbnail')[0].split('/').pop();
var linkType = $(this).css('background-image').split('/thumbnail')[0].split('/'+bookID)[0].split('/').pop();
type = linkType+"_selection";
if ((idArray.indexOf(bookID) === -1)&&(bookID !== "none")){
idArray.push(bookID);
}
});
if (idArray.length === 0) {
return;
}
if(window.location.href.indexOf("/readlists/") > -1){
type = "readlists_books_selection";
id = window.location.href.split('/readlists/').pop()+";";
}
idArray.forEach(function(item) {
id += item+";";
});
}else{
id = $borderedCells.css('background-image').split('/thumbnail')[0].split('/').pop();
if(window.location.href.indexOf("/readlists/") > -1){
type = "readlists_books_selection";
var listID = window.location.href.split('/readlists/').pop()+";";
id = listID+id;
}else{
type = $borderedCells.css('background-image').split('/thumbnail')[0].split('/'+id)[0].split('/').pop();
}
}
$("#logContainer").remove();
var ws = new WebSocket(websocket+type+"&id="+id);
ws.onopen = function() {
overlay.prependTo('.container:first');
$('#toolbarButton').blur();
$("#counter").hide();
$("#counterText").empty();
themeButton();
if(type.includes("_selection")){
$('#thumbnail').css('background-image', 'url('+location.protocol+'//'+location.host+'/api/v1/'+type.split("_")[0]+'/'+id.split(';')[0]+'/thumbnail)');
}else{
$('#thumbnail').css('background-image', 'url('+location.protocol+'//'+location.host+'/api/v1/'+type+'/'+id+'/thumbnail)');
}
$('#progressbar').progressbar({value:0});
$('.ui-progressbar-value').css('height', '100%').css('background','var(--v-secondary-base)');
};
ws.onclose = function() {
setTimeout(function(){
$('#log').empty();
$('#logContainer').remove();
}, 5000);
};
ws.onmessage = function(event) {
if (event.data.startsWith("BOOKID:")){
$('#thumbnail').css('background-image', 'url('+location.protocol+'//'+location.host+'/api/v1/books/'+event.data.split("BOOKID:")[1]+'/thumbnail)');
}else if (event.data.startsWith("PROGRESS:")){
$('#progressbar').progressbar({value:parseFloat(event.data.split("PROGRESS:")[1])});
}else if (event.data.startsWith("COUNTER:")){
$('#counter').show();
$('#counter > span').text(event.data.split("COUNTER:")[1]);
}else if (event.data.startsWith("FREESPACE:")){
$('.iosstats').show();
$('#freespace').text(event.data.split("FREESPACE:")[1]);
}else if (event.data.startsWith("TOTALSPACE:")){
$('.iosstats').show();
$('#capacity').text(event.data.split("TOTALSPACE:")[1]);
}else{
log(event.data);
}
};
});
}
}
waitForKeyElements (".sticky-bar .mdi-close", addToolbarButton);
function themeButton () {
$(".tmelement").removeClass('theme--dark theme--light');
var themeToggle = $('label:contains("Theme")')[0].htmlFor;
if ($('#'+themeToggle).parent().parent().find('input')[1].value === "theme.dark"){
$(".tmelement").addClass('theme--dark');
} else if ($('#'+themeToggle).parent().parent().find('input')[1].value === "theme.light"){
$(".tmelement").addClass('theme--light');
}
}
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function() {
themeButton();
});
});
function log(msg) {
if ((msg.endsWith("...")) || (msg.endsWith(": "))) {
document.getElementById('log').textContent += msg;
}else{
document.getElementById('log').textContent += msg + '\n';
}
$('#log').scrollTop($('#log')[0].scrollHeight);
}
#!/bin/bash
KOMGA_URL="http://192.168.1.100:8080"
KOMGA_USER="why.is.this@anemail.com"
KOMGA_PASS="password"
IPAD_IP="192.168.1.10"
SSH_PASS="password"
FILENAME_ARRAY=()
PROGRESS=0
TOTALSIZE=0
FILE_CHANGES=false
SSH_TEST=$(sshpass -p $SSH_PASS ssh -o ConnectTimeout=3 root@$IPAD_IP 'for p in $(find /var/mobile/Containers/Data -type f -name *plist); do if grep -qi chunky $p 2>/dev/null; then echo $p; fi; done' 2>&1)
if [[ $SSH_TEST == *refused* || $SSH_TEST == *timed* || $SSH_TEST == *Unable* ]]; then
echo "No SSH server found, exiting"
exit 1
else
CHUNKY_PATH=`echo $SSH_TEST | cut -d '.' -f1`
if [ -z "$CHUNKY_PATH" ]; then
echo "Chunky location not found"
exit 1
fi
fi
DF=($(sshpass -p $SSH_PASS ssh root@$IPAD_IP "df -k /dev/disk0s1s2 | tail -1" 2>&1))
TOTAL_CAPACITY=${DF[1]}
TOTAL_CAPACITY=`bc <<< 'scale=2; '$TOTAL_CAPACITY'/1024'`
if [ `bc <<< $TOTAL_CAPACITY' < 1024'` == 1 ]; then
TOTAL_CAPACITY_DISPLAY=$TOTAL_CAPACITY" MB"
else
TOTAL_CAPACITY_DISPLAY=`bc <<< 'scale=2; '$TOTAL_CAPACITY'/1024'`
TOTAL_CAPACITY_DISPLAY=$TOTAL_CAPACITY_DISPLAY" GB"
fi
echo "TOTALSPACE:Capacity: "$TOTAL_CAPACITY_DISPLAY
FREE_SPACE=${DF[3]}
FREE_SPACE=`bc <<< 'scale=2; '$FREE_SPACE'/1024'`
if [ `bc <<< $FREE_SPACE' < 1024'` == 1 ]; then
FREE_SPACE_DISPLAY=$FREE_SPACE" MB"
else
FREE_SPACE_DISPLAY=`bc <<< 'scale=2; '$FREE_SPACE'/1024'`
FREE_SPACE_DISPLAY=$FREE_SPACE_DISPLAY" GB"
fi
echo "FREESPACE:Available: "$FREE_SPACE_DISPLAY
if [ $2 == "readlists" ]; then
LIST_JSON=`curl -X 'GET' \
$KOMGA_URL'/api/v1/readlists/'$1 \
-H 'accept: application/json' \
-u $KOMGA_USER:$KOMGA_PASS -s`
echo "Reading list: "
elif [ $2 == "series" ]; then
LIST_JSON=`curl -X 'GET' \
$KOMGA_URL'/api/v1/series/'$1 \
-H 'accept: application/json' \
-u $KOMGA_USER:$KOMGA_PASS -s`
echo "Series: "
elif [ $2 == "books" ]; then
LIST_JSON=`curl -X 'GET' \
$KOMGA_URL'/api/v1/books/'$1 \
-H 'accept: application/json' \
-u $KOMGA_USER:$KOMGA_PASS -s`
echo "Selected book: "
elif [ $2 == "books_selection" ]||[ $2 == "readlists_books_selection" ]||[ $2 == "series_selection" ]||[ $2 == "readlists_selection" ]; then
set -f
if [ $2 == "series_selection" ]; then
SERIES_IDS=(${1//;/ })
SERIESLIST_LENGTH=${#SERIES_IDS[@]}
i=0
echo "Loading series:"
while [ $i -lt $SERIESLIST_LENGTH ];
do
LIST_JSON=`curl -X 'GET' \
$KOMGA_URL'/api/v1/series/'${SERIES_IDS[i]} \
-H 'accept: application/json' \
-u $KOMGA_USER:$KOMGA_PASS -s`
SERIES_LIST_JSON=`curl -X 'GET' \
$KOMGA_URL'/api/v1/series/'${SERIES_IDS[i]}'/books?unpaged=true' \
-H 'accept: application/json' \
-u $KOMGA_USER:$KOMGA_PASS -s`
LIST_NAME=`echo $LIST_JSON | jq .name | tr -d '"'`
echo '"'$LIST_NAME'"...'
BOOKLIST_LENGTH=`jq '.content | length' <<< $SERIES_LIST_JSON`
x=0
while [ $x -lt $BOOKLIST_LENGTH ];
do
FILENAME=`basename "$(echo $SERIES_LIST_JSON | jq '.content['$x'].url')" .cbz | cut -d'"' -f 1 | tr ' ' '_'`
BOOK_ID=`echo $SERIES_LIST_JSON | jq -r '.content['$x'].id'`
FILESIZE=`echo $SERIES_LIST_JSON | jq -r '.content['$x'].sizeBytes'`
TOTALSIZE=`bc <<< $TOTALSIZE'+'$FILESIZE`
BOOK_IDS+=("$BOOK_ID")
FILENAME_ARRAY+=("$FILENAME")
let x++
done
echo "Done"
let i++
done
elif [ $2 == "readlists_selection" ]; then
LIST_IDS=(${1//;/ })
BOOK_IDS=()
LIST_NAMES_ARRAY=()
else
BOOK_IDS=(${1//;/ })
fi
if [ $2 == "readlists_selection" ]; then
LIST_COUNT=${#LIST_IDS[@]}
i=0
echo "Loading reading lists:"
while [ $i -lt $LIST_COUNT ];
do
LIST_JSON=`curl -X 'GET' \
$KOMGA_URL'/api/v1/readlists/'${LIST_IDS[i]} \
-H 'accept: application/json' \
-u $KOMGA_USER:$KOMGA_PASS -s`
READLIST_JSON=`curl -X 'GET' \
$KOMGA_URL'/api/v1/readlists/'${LIST_IDS[i]}'/books?unpaged=true' \
-H 'accept: application/json' \
-u $KOMGA_USER:$KOMGA_PASS -s`
LIST_NAME=`echo $LIST_JSON | jq .name | tr -d '"'`
echo '"'$LIST_NAME'"...'
BOOKLIST_LENGTH=`jq '.content | length' <<< $READLIST_JSON`
x=0
while [ $x -lt $BOOKLIST_LENGTH ];
do
FILENAME=`basename "$(echo $READLIST_JSON | jq '.content['$x'].url')" .cbz | cut -d'"' -f 1 | tr ' ' '_'`
BOOK_ID=`echo $READLIST_JSON | jq -r '.content['$x'].id'`
FILESIZE=`echo $READLIST_JSON | jq -r '.content['$x'].sizeBytes'`
TOTALSIZE=`bc <<< $TOTALSIZE'+'$FILESIZE`
BOOK_IDS+=("$BOOK_ID")
LIST_NUM=`printf "%03d\n" $(($x+1))`
FILENAME=${LIST_NUM}_-_${FILENAME}
FILENAME_ARRAY+=("$FILENAME")
LIST_NAMES_ARRAY+=("$LIST_NAME")
let x++
done
echo "Done"
let i++
done
fi
if [ $2 == "readlists_books_selection" ]; then
LIST_ID=${BOOK_IDS[0]}
unset 'BOOK_IDS[0]'
BOOK_IDS=(${BOOK_IDS[@]})
LIST_JSON=`curl -X 'GET' \
$KOMGA_URL'/api/v1/readlists/'$LIST_ID \
-H 'accept: application/json' \
-u $KOMGA_USER:$KOMGA_PASS -s`
LIST_BOOK_IDS=( $(jq -cr .bookIds[] <<< $LIST_JSON) )
LIST_NAME=`echo $LIST_JSON | jq .name | tr -d '"'`
echo 'Reading list: "'$LIST_NAME'"'
fi
BOOKLIST_LENGTH=${#BOOK_IDS[@]}
echo "COUNTER:"$BOOKLIST_LENGTH
if [ $BOOKLIST_LENGTH == "1" ]; then
echo 'Selection has '$BOOKLIST_LENGTH' book'
else
echo 'Selection has '$BOOKLIST_LENGTH' books'
fi
if [ $2 == "readlists_selection" ]||[ $2 == "readlists_books_selection" ]; then
PROGRESS_AMOUNT=`bc <<< 'scale=2; 90/'$BOOKLIST_LENGTH`
else
PROGRESS_AMOUNT=`bc <<< 'scale=2; 100/'$BOOKLIST_LENGTH`
fi
if [ $2 != "series_selection" ]&&[ $2 != "readlists_selection" ]; then
i=0
while [ $i -lt $BOOKLIST_LENGTH ];
do
if [ $2 == "readlists_books_selection" ]; then
for x in "${!LIST_BOOK_IDS[@]}";
do
if [[ "${LIST_BOOK_IDS[$x]}" = "${BOOK_IDS[i]}" ]];
then
LIST_NUM=`printf "%03d\n" $(($x+1))`
fi
done
fi
FILE_LIST_JSON=`curl -X 'GET' \
$KOMGA_URL'/api/v1/books/'${BOOK_IDS[i]} \
-H 'accept: application/json' \
-u $KOMGA_USER:$KOMGA_PASS -s`
STATUS=`echo $FILE_LIST_JSON | jq .status`
FILESIZE=`echo $FILE_LIST_JSON | jq -r '.sizeBytes'`
TOTALSIZE=`bc <<< $TOTALSIZE'+'$FILESIZE`
if [ $STATUS == "404" ]; then
echo "Unknown Komga file ID"
exit 1
fi
FILENAME=`basename "$(echo $FILE_LIST_JSON | jq .url)" .cbz | cut -d'"' -f 1 | tr ' ' '_'`
if [ $2 == "readlists_books_selection" ]; then
FILENAME=$LIST_NUM"_-_"$FILENAME
fi
FILENAME_ARRAY+=("$FILENAME")
let i++
done
fi
TOTALSIZE=`bc <<< 'scale=2; '$TOTALSIZE'/1024/1024'`
if [ `bc <<< $TOTALSIZE' < 1024'` == 1 ]; then
TOTALSIZE_DISPLAY=$TOTALSIZE" MB"
else
TOTALSIZE_DISPLAY=`bc <<< 'scale=2; '$TOTALSIZE'/1024'`
TOTALSIZE_DISPLAY=$TOTALSIZE_DISPLAY" GB"
fi
echo "Size: "$TOTALSIZE_DISPLAY
fi
if [ $2 != "books_selection" ]&&[ $2 != "series_selection" ]&&[ $2 != "readlists_selection" ]&&[ $2 != "readlists_books_selection" ]; then
STATUS=`jq .status <<< $LIST_JSON`
if [ $STATUS == "404" ]; then
echo "Unknown Komga "$2" ID"
exit 1
fi
LIST_NAME=`echo $LIST_JSON | jq .name | tr -d '"'`
echo '"'$LIST_NAME'"'
fi
if [ $2 == "readlists" ]||[ $2 == "series" ]; then
BOOK_IDS=()
if [ $2 == "readlists" ]; then
BOOKLIST_JSON=`curl -X 'GET' \
$KOMGA_URL'/api/v1/readlists/'$1'/books?unpaged=true' \
-H 'accept: application/json' \
-u $KOMGA_USER:$KOMGA_PASS -s`
elif [ $2 == "series" ]; then
BOOKLIST_JSON=`curl -X 'GET' \
$KOMGA_URL'/api/v1/series/'$1'/books?unpaged=true' \
-H 'accept: application/json' \
-u $KOMGA_USER:$KOMGA_PASS -s`
fi
BOOKLIST_LENGTH=`jq '.content | length' <<< $BOOKLIST_JSON`
if [ $2 == "readlists" ]; then
PROGRESS_AMOUNT=`bc <<< 'scale=2; 90/'$BOOKLIST_LENGTH`
elif [ $2 == "series" ]; then
PROGRESS_AMOUNT=`bc <<< 'scale=2; 100/'$BOOKLIST_LENGTH`
fi
echo "COUNTER:"$BOOKLIST_LENGTH
if [ $2 == "readlists" ]; then
TYPE="Reading list"
elif [ $2 == "series" ]; then
TYPE="Series"
fi
if [ $BOOKLIST_LENGTH == "1" ]; then
echo $TYPE' has '$BOOKLIST_LENGTH' book'
else
echo $TYPE' has '$BOOKLIST_LENGTH' books'
fi
echo "Processing book list..."
i=0
while [ $i -lt $BOOKLIST_LENGTH ];
do
FILENAME=`basename "$(echo $BOOKLIST_JSON | jq '.content['$i'].url')" .cbz | cut -d'"' -f 1 | tr ' ' '_'`
BOOK_ID=`echo $BOOKLIST_JSON | jq -r '.content['$i'].id'`
FILESIZE=`echo $BOOKLIST_JSON | jq -r '.content['$i'].sizeBytes'`
TOTALSIZE=`bc <<< $TOTALSIZE'+'$FILESIZE`
BOOK_IDS+=("$BOOK_ID")
if [ $2 == "readlists" ]; then
LIST_NUM=`printf "%03d\n" $(($i+1))`
FILENAME=${LIST_NUM}_-_${FILENAME}
fi
FILENAME_ARRAY+=("$FILENAME")
let i++
done
echo "Done"
TOTALSIZE=`bc <<< 'scale=2; '$TOTALSIZE'/1024/1024'`
if [ `bc <<< $TOTALSIZE' < 1024'` == 1 ]; then
TOTALSIZE_DISPLAY=$TOTALSIZE" MB"
else
TOTALSIZE_DISPLAY=`bc <<< 'scale=2; '$TOTALSIZE'/1024'`
TOTALSIZE_DISPLAY=$TOTALSIZE_DISPLAY" GB"
fi
echo "Size: "$TOTALSIZE_DISPLAY
elif [ $2 == "books" ]; then
FILESIZE=`echo $LIST_JSON | jq -r '.sizeBytes'`
FILESIZE=`bc <<< 'scale=2; '$FILESIZE'/1024/1024'`
echo "Size: "$FILESIZE" MB"
LIST_FILENAME=`basename "$(echo $LIST_JSON | jq .url)" .cbz | cut -d'"' -f 1 | tr ' ' '_'`
BOOK_IDS=("$1")
fi
if [ `bc <<< $TOTALSIZE' > '$FREE_SPACE` == 1 ]; then
echo
echo "This is larger than the available free space on the iPad"
exit 1
fi
if [ $2 == "readlists" ]||[ $2 == "readlists_selection" ]||[ $2 == "readlists_books_selection" ]; then
echo
echo "Activating Chunky"
sshpass -p $SSH_PASS ssh root@$IPAD_IP 'open com.mike-ferenduros.Chunky-Comic-Reader'
echo "Turning off Auto-Lock"
sshpass -p $SSH_PASS ssh root@$IPAD_IP 'activator send switch-off.com.a3tweaks.switch.autolock'
PROGRESS=`bc <<< 'scale=2; '$PROGRESS'+2'`
echo "PROGRESS:"$PROGRESS
fi
echo
echo "Transferring files"
for i in ${!BOOK_IDS[@]}; do
if [ $2 != "books" ]; then
LIST_FILENAME=${FILENAME_ARRAY[$i]}
fi
echo "BOOKID:"${BOOK_IDS[$i]}
LIST_FILENAME=`echo $LIST_FILENAME | tr '_' ' '`
echo $(($i+1))". \""$LIST_FILENAME"\"..."
if ! (sshpass -p $SSH_PASS ssh root@$IPAD_IP stat \"$CHUNKY_PATH/Documents/$LIST_FILENAME\" \> /dev/null 2\>\&1) ; then
sshpass -p $SSH_PASS ssh root@$IPAD_IP 'curl -X "GET" '$KOMGA_URL'"/api/v1/books/"'${BOOK_IDS[$i]}'"/file" -H "accept: application/octet-stream" -u '$KOMGA_USER:$KOMGA_PASS' --output "'$CHUNKY_PATH/Documents/$LIST_FILENAME'"'
echo "Done"
DF=($(sshpass -p $SSH_PASS ssh root@$IPAD_IP "df -k /dev/disk0s1s2 | tail -1" 2>&1))
FREE_SPACE=${DF[3]}
FREE_SPACE=`bc <<< 'scale=2; '$FREE_SPACE'/1024'`
if [ `bc <<< $FREE_SPACE' < 1024'` == 1 ]; then
FREE_SPACE_DISPLAY=$FREE_SPACE" MB"
else
FREE_SPACE_DISPLAY=`bc <<< 'scale=2; '$FREE_SPACE'/1024'`
FREE_SPACE_DISPLAY=$FREE_SPACE_DISPLAY" GB"
fi
echo "FREESPACE:Available: "$FREE_SPACE_DISPLAY
FILE_CHANGES=true
else
echo "Skipped (Already exists)"
fi
PROGRESS=`bc <<< 'scale=2; '$PROGRESS'+'$PROGRESS_AMOUNT`
echo "PROGRESS:"$PROGRESS
done
if [ $2 == "readlists" ]||[ $2 == "readlists_selection" ]||[ $2 == "readlists_books_selection" ]; then
if [ $FILE_CHANGES == true ]; then
echo
echo "Waiting for Chunky to finish loading files"
sleep 10
echo "Turning Auto-Lock back on"
sshpass -p $SSH_PASS ssh root@$IPAD_IP 'activator send switch-on.com.a3tweaks.switch.autolock'
echo "Killing Chunky"
sshpass -p $SSH_PASS ssh root@$IPAD_IP 'killall "Chunky Comic Reader"'
echo "Editing Database"
sshpass -p $SSH_PASS scp root@$IPAD_IP:$CHUNKY_PATH/Library/PrivateDB/db-011.sqlite3 . 2>&1
for i in ${!FILENAME_ARRAY[@]}; do
if [ $2 == "readlists_selection" ]; then
LIST_NAME=`echo ${LIST_NAMES_ARRAY[$i]} | tr '_' ' '`
fi
LIST_NAME_SIMPLE=`echo $LIST_NAME | tr -dc '[:alnum:]\n\r ' | tr '[:upper:]' '[:lower:]'`
filename=`echo ${FILENAME_ARRAY[$i]} | tr '_' ' '`
sqlite3 db-011.sqlite3 <<END_SQL
update Book set manualGroupName='$LIST_NAME', groupName='$LIST_NAME_SIMPLE' where filename='$filename';
END_SQL
done
sshpass -p $SSH_PASS scp -r db-011.sqlite3 root@$IPAD_IP:$CHUNKY_PATH/Library/PrivateDB/ 2>&1
echo "Relaunching Chunky"
sshpass -p $SSH_PASS ssh root@$IPAD_IP 'open com.mike-ferenduros.Chunky-Comic-Reader'
rm db-011.sqlite3
else
echo
echo "No database changes necessary"
echo "Turning Auto-Lock back on"
sshpass -p $SSH_PASS ssh root@$IPAD_IP 'activator send switch-on.com.a3tweaks.switch.autolock'
fi
fi
echo
echo "PROGRESS:100"
echo "Done!"
#!/bin/bash
OIFS=$IFS
IFS='&' read -r -a query <<< "$QUERY_STRING"
ID=`printf '%s\0' "${query[@]}" | grep -F -z 'id' | rev | cut -d"=" -f1 | rev`
TYPE=`printf '%s\0' "${query[@]}" | grep -F -z 'type' | rev | cut -d"=" -f1 | rev`
./newDownloader.sh $ID $TYPE
IFS=$OIFS
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment