mirror of
https://github.com/hkalexling/Mango.git
synced 2025-08-02 02:45:29 -04:00
Revert "Subscription manager"
This reverts commit a612500b0fabf7259a5ee0c841b0157d191e5bdd.
This commit is contained in:
parent
cd8944ed2d
commit
1973564272
@ -1,31 +0,0 @@
|
||||
class CreateSubscription < MG::Base
|
||||
def up : String
|
||||
# We allow multiple subscriptions for the same manga.
|
||||
# This can be useful for example when you want to download from multiple
|
||||
# groups.
|
||||
<<-SQL
|
||||
CREATE TABLE subscription (
|
||||
id INTEGER PRIMARY KEY,
|
||||
manga_id INTEGER NOT NULL,
|
||||
language TEXT,
|
||||
group_id INTEGER,
|
||||
min_volume INTEGER,
|
||||
max_volume INTEGER,
|
||||
min_chapter INTEGER,
|
||||
max_chapter INTEGER,
|
||||
last_checked INTEGER NOT NULL,
|
||||
created_at INTEGER NOT NULL,
|
||||
username TEXT NOT NULL,
|
||||
FOREIGN KEY (username) REFERENCES users (username)
|
||||
ON UPDATE CASCADE
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
SQL
|
||||
end
|
||||
|
||||
def down : String
|
||||
<<-SQL
|
||||
DROP TABLE subscription;
|
||||
SQL
|
||||
end
|
||||
end
|
@ -280,100 +280,6 @@ const downloadComponent = () => {
|
||||
UIkit.modal($('#modal').get(0)).hide();
|
||||
this.searchInput = id;
|
||||
this.search();
|
||||
},
|
||||
|
||||
subscribe(langConfirmed = false, groupConfirmed = false) {
|
||||
const filters = {
|
||||
manga: this.data.id,
|
||||
language: this.langChoice === 'All' ? null : this.langChoice,
|
||||
group: this.groupChoice === 'All' ? null : this.groupChoice,
|
||||
volume: this.volumeRange === '' ? null : this.volumeRange,
|
||||
chapter: this.chapterRange === '' ? null : this.chapterRange
|
||||
};
|
||||
|
||||
// Get group ID
|
||||
if (filters.group) {
|
||||
this.data.chapters.forEach(chp => {
|
||||
const gid = chp.groups[filters.group];
|
||||
if (gid) {
|
||||
filters.groupId = gid;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Parse range values
|
||||
if (filters.volume) {
|
||||
[filters.volumeMin, filters.volumeMax] = this.parseRange(filters.volume);
|
||||
}
|
||||
if (filters.chapter) {
|
||||
[filters.chapterMin, filters.chapterMax] = this.parseRange(filters.chapter);
|
||||
}
|
||||
|
||||
if (!filters.language && !langConfirmed) {
|
||||
UIkit.modal.confirm('You didn\'t specify a language in the filtering rules. This might cause Mango to download chapters that are not in your preferred language. Are you sure you want to continue?', {
|
||||
labels: {
|
||||
ok: 'Yes',
|
||||
cancel: 'Cancel'
|
||||
}
|
||||
}).then(() => {
|
||||
this.subscribe(true, groupConfirmed);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!filters.group && !groupConfirmed) {
|
||||
UIkit.modal.confirm('You didn\'t specify a group in the filtering rules. This might cause Mango to download multiple versions of the same chapter. Are you sure you want to continue?', {
|
||||
labels: {
|
||||
ok: 'Yes',
|
||||
cancel: 'Cancel'
|
||||
}
|
||||
}).then(() => {
|
||||
this.subscribe(langConfirmed, true);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const mangaURL = `${mangadex_base_url}/manga/${filters.manga}`;
|
||||
|
||||
console.log(filters);
|
||||
UIkit.modal.confirm(`All <strong>FUTURE</strong> chapters matching the following filters will be downloaded:<br>
|
||||
<ul>
|
||||
<li>Manga ID: ${filters.manga}</li>
|
||||
<li>Language: ${filters.language || 'all'}</li>
|
||||
<li>Group: ${filters.group || 'all'}</li>
|
||||
<li>Volume: ${filters.volume || 'all'}</li>
|
||||
<li>Chapter: ${filters.chapter || 'all'}</li>
|
||||
</ul>
|
||||
|
||||
<strong>IMPORTANT:</strong> Please make sure you are following the manga on MangaDex, otherwise Mango won't be able to receive any updates. To follow it, visit <a href="${mangaURL}">${mangaURL}</a> and click "Follow".
|
||||
`, {
|
||||
labels: {
|
||||
ok: 'Confirm',
|
||||
cancel: 'Cancel'
|
||||
}
|
||||
}).then(() => {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: `${base_url}api/admin/mangadex/subscriptions`,
|
||||
data: JSON.stringify({
|
||||
subscription: filters
|
||||
}),
|
||||
contentType: "application/json",
|
||||
dataType: 'json'
|
||||
})
|
||||
.done(data => {
|
||||
console.log(data);
|
||||
if (data.error) {
|
||||
alert('danger', `Failed to subscribe. Error: ${data.error}`);
|
||||
return;
|
||||
}
|
||||
alert('success', `You've successfully subscribed to this manga! You can view and manage your subscriptions on the <a href="${base_url}download/subscription">subscription manager page</a>.`);
|
||||
})
|
||||
.fail((jqXHR, status) => {
|
||||
alert('danger', `Failed to subscribe. Error: [${jqXHR.status}] ${jqXHR.statusText}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -54,7 +54,7 @@ shards:
|
||||
|
||||
mangadex:
|
||||
git: https://github.com/hkalexling/mangadex.git
|
||||
version: 0.11.0+git.commit.f5b0d64fbb138879fb9228b6e9ff34ec97c3e824
|
||||
version: 0.9.0+git.commit.a8e5deb3e6f882f5bc0f4de66e0f6c20aa98a8a6
|
||||
|
||||
mg:
|
||||
git: https://github.com/hkalexling/mg.git
|
||||
|
@ -33,10 +33,8 @@ class Config
|
||||
"download_retries" => 4,
|
||||
"download_queue_db_path" => File.expand_path("~/mango/queue.db",
|
||||
home: true),
|
||||
"chapter_rename_rule" => "[Vol.{volume} ]" \
|
||||
"[Ch.{chapter} ]{title|id}",
|
||||
"chapter_rename_rule" => "[Vol.{volume} ][Ch.{chapter} ]{title|id}",
|
||||
"manga_rename_rule" => "{title}",
|
||||
"subscription_update_interval_hours" => 24,
|
||||
}
|
||||
|
||||
@@singlet : Config?
|
||||
|
@ -42,25 +42,6 @@ class Library
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
subscription_interval = Config.current
|
||||
.mangadex["subscription_update_interval_hours"].as Int32
|
||||
unless subscription_interval < 1
|
||||
spawn do
|
||||
loop do
|
||||
subscriptions = Storage.default.subscriptions
|
||||
Logger.info "Checking MangaDex for updates on " \
|
||||
"#{subscriptions.size} subscriptions"
|
||||
added_count = 0
|
||||
subscriptions.each do |sub|
|
||||
added_count += sub.check_for_updates
|
||||
end
|
||||
Logger.info "Subscription update completed. Added #{added_count} " \
|
||||
"chapters to the download queue"
|
||||
sleep subscription_interval.hours
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def titles
|
||||
|
@ -56,39 +56,5 @@ module MangaDex
|
||||
hash["full_title"] = JSON::Any.new full_title
|
||||
hash.to_json
|
||||
end
|
||||
|
||||
# We don't need to rename the manga title here. It will be renamed in
|
||||
# src/mangadex/downloader.cr
|
||||
def to_job : Queue::Job
|
||||
Queue::Job.new(
|
||||
id.to_s,
|
||||
manga_id.to_s,
|
||||
full_title,
|
||||
manga_title,
|
||||
Queue::JobStatus::Pending,
|
||||
Time.unix timestamp
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
struct User
|
||||
def updates_after(time : Time, &block : Chapter ->)
|
||||
page = 1
|
||||
stopped = false
|
||||
until stopped
|
||||
chapters = followed_updates(page: page).chapters
|
||||
return if chapters.empty?
|
||||
chapters.each do |c|
|
||||
if time > Time.unix c.timestamp
|
||||
stopped = true
|
||||
break
|
||||
end
|
||||
yield c
|
||||
end
|
||||
page += 1
|
||||
# Let's not DDOS MangaDex :)
|
||||
sleep 5.seconds
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -986,147 +986,23 @@ struct APIRouter
|
||||
Koa.tags ["admin", "mangadex"]
|
||||
get "/api/admin/mangadex/search" do |env|
|
||||
begin
|
||||
username = get_username env
|
||||
token, expires = Storage.default.get_md_token username
|
||||
|
||||
unless expires && token
|
||||
raise "No token found for user #{username}"
|
||||
end
|
||||
|
||||
client = MangaDex::Client.from_config
|
||||
client.token = token
|
||||
client.token_expires = expires
|
||||
|
||||
query = env.params.query["query"]
|
||||
|
||||
send_json env, {
|
||||
"success" => true,
|
||||
"error" => nil,
|
||||
"manga" => get_client(env).partial_search query,
|
||||
}.to_json
|
||||
rescue e
|
||||
Logger.error e
|
||||
send_json env, {
|
||||
"success" => false,
|
||||
"error" => e.message,
|
||||
}.to_json
|
||||
end
|
||||
end
|
||||
|
||||
Koa.describe "Lists all MangaDex subscriptions"
|
||||
Koa.response 200, schema: {
|
||||
"success" => Bool,
|
||||
"error" => String?,
|
||||
"subscriptions?" => [{
|
||||
"id" => Int64,
|
||||
"username" => String,
|
||||
"manga_id" => Int64,
|
||||
"language" => String?,
|
||||
"group_id" => Int64?,
|
||||
"min_volume" => Int64?,
|
||||
"max_volume" => Int64?,
|
||||
"min_chapter" => Int64?,
|
||||
"max_chapter" => Int64?,
|
||||
"last_checked" => Int64,
|
||||
"created_at" => Int64,
|
||||
}],
|
||||
}
|
||||
Koa.tags ["admin", "mangadex", "subscriptions"]
|
||||
get "/api/admin/mangadex/subscriptions" do |env|
|
||||
begin
|
||||
send_json env, {
|
||||
"success" => true,
|
||||
"error" => nil,
|
||||
"subscriptions" => Storage.default.subscriptions,
|
||||
}.to_json
|
||||
rescue e
|
||||
Logger.error e
|
||||
send_json env, {
|
||||
"success" => false,
|
||||
"error" => e.message,
|
||||
}.to_json
|
||||
end
|
||||
end
|
||||
|
||||
Koa.describe "Creates a new MangaDex subscription"
|
||||
Koa.body schema: {
|
||||
"subscription" => {
|
||||
"manga" => Int64,
|
||||
"language" => String?,
|
||||
"groupId" => Int64?,
|
||||
"volumeMin" => Int64?,
|
||||
"volumeMax" => Int64?,
|
||||
"chapterMin" => Int64?,
|
||||
"chapterMax" => Int64?,
|
||||
},
|
||||
}
|
||||
Koa.response 200, schema: {
|
||||
"success" => Bool,
|
||||
"error" => String?,
|
||||
}
|
||||
Koa.tags ["admin", "mangadex", "subscriptions"]
|
||||
post "/api/admin/mangadex/subscriptions" do |env|
|
||||
begin
|
||||
json = env.params.json["subscription"].as Hash(String, JSON::Any)
|
||||
sub = Subscription.new json["manga"].as_i64, get_username env
|
||||
sub.language = json["language"]?.try &.as_s?
|
||||
sub.group_id = json["groupId"]?.try &.as_i64?
|
||||
sub.min_volume = json["volumeMin"]?.try &.as_i64?
|
||||
sub.max_volume = json["volumeMax"]?.try &.as_i64?
|
||||
sub.min_chapter = json["chapterMin"]?.try &.as_i64?
|
||||
sub.max_chapter = json["chapterMax"]?.try &.as_i64?
|
||||
|
||||
Storage.default.save_subscription sub
|
||||
|
||||
send_json env, {
|
||||
"success" => true,
|
||||
"error" => nil,
|
||||
}.to_json
|
||||
rescue e
|
||||
Logger.error e
|
||||
send_json env, {
|
||||
"success" => false,
|
||||
"error" => e.message,
|
||||
}.to_json
|
||||
end
|
||||
end
|
||||
|
||||
Koa.describe "Deletes a MangaDex subscription identified by `id`", <<-MD
|
||||
Does nothing if the subscription was not created by the current user.
|
||||
MD
|
||||
Koa.response 200, schema: {
|
||||
"success" => Bool,
|
||||
"error" => String?,
|
||||
}
|
||||
Koa.tags ["admin", "mangadex", "subscriptions"]
|
||||
delete "/api/admin/mangadex/subscriptions/:id" do |env|
|
||||
begin
|
||||
id = env.params.url["id"].to_i64
|
||||
Storage.default.delete_subscription id, get_username env
|
||||
send_json env, {
|
||||
"success" => true,
|
||||
"error" => nil,
|
||||
}.to_json
|
||||
rescue e
|
||||
Logger.error e
|
||||
send_json env, {
|
||||
"success" => false,
|
||||
"error" => e.message,
|
||||
}.to_json
|
||||
end
|
||||
end
|
||||
|
||||
Koa.describe "Triggers an update for a MangaDex subscription identified by `id`", <<-MD
|
||||
Does nothing if the subscription was not created by the current user.
|
||||
MD
|
||||
Koa.response 200, schema: {
|
||||
"success" => Bool,
|
||||
"error" => String?,
|
||||
}
|
||||
Koa.tags ["admin", "mangadex", "subscriptions"]
|
||||
post "/api/admin/mangadex/subscriptions/check/:id" do |env|
|
||||
begin
|
||||
id = env.params.url["id"].to_i64
|
||||
username = get_username env
|
||||
sub = Storage.default.get_subscription id, username
|
||||
unless sub
|
||||
raise "Subscription with id #{id} not found under user #{username}"
|
||||
end
|
||||
spawn do
|
||||
sub.check_for_updates
|
||||
end
|
||||
send_json env, {
|
||||
"success" => true,
|
||||
"error" => nil,
|
||||
"manga" => client.partial_search query,
|
||||
}.to_json
|
||||
rescue e
|
||||
Logger.error e
|
||||
|
@ -96,12 +96,6 @@ struct MainRouter
|
||||
end
|
||||
end
|
||||
|
||||
get "/download/subscription" do |env|
|
||||
mangadex_base_url = Config.current.mangadex["base_url"]
|
||||
username = get_username env
|
||||
layout "subscription"
|
||||
end
|
||||
|
||||
get "/" do |env|
|
||||
begin
|
||||
username = get_username env
|
||||
|
@ -5,7 +5,6 @@ require "base64"
|
||||
require "./util/*"
|
||||
require "mg"
|
||||
require "../migration/*"
|
||||
require "./subscription"
|
||||
|
||||
def hash_password(pw)
|
||||
Crypto::Bcrypt::Password.create(pw).to_s
|
||||
@ -15,9 +14,6 @@ def verify_password(hash, pw)
|
||||
(Crypto::Bcrypt::Password.new hash).verify pw
|
||||
end
|
||||
|
||||
SUB_ATTR = %w(manga_id language group_id min_volume max_volume min_chapter
|
||||
max_chapter username)
|
||||
|
||||
class Storage
|
||||
@@insert_entry_ids = [] of IDTuple
|
||||
@@insert_title_ids = [] of IDTuple
|
||||
@ -549,70 +545,6 @@ class Storage
|
||||
{token, expires}
|
||||
end
|
||||
|
||||
def save_subscription(sub : Subscription)
|
||||
MainFiber.run do
|
||||
get_db do |db|
|
||||
{% begin %}
|
||||
db.exec "insert into subscription (#{SUB_ATTR.join ","}, " \
|
||||
"last_checked, created_at) values " \
|
||||
"(#{Array.new(SUB_ATTR.size + 2, "?").join ","})",
|
||||
{% for type in SUB_ATTR %}
|
||||
sub.{{type.id}},
|
||||
{% end %}
|
||||
sub.last_checked.to_unix, sub.created_at.to_unix
|
||||
{% end %}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def subscriptions : Array(Subscription)
|
||||
subs = [] of Subscription
|
||||
MainFiber.run do
|
||||
get_db do |db|
|
||||
db.query "select * from subscription" do |rs|
|
||||
subs += Subscription.from_rs rs
|
||||
end
|
||||
end
|
||||
end
|
||||
subs
|
||||
end
|
||||
|
||||
def delete_subscription(id : Int64, username : String)
|
||||
MainFiber.run do
|
||||
get_db do |db|
|
||||
db.exec "delete from subscription where id = (?) and username = (?)",
|
||||
id, username
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_subscription(id : Int64, username : String) : Subscription?
|
||||
sub = nil
|
||||
MainFiber.run do
|
||||
get_db do |db|
|
||||
db.query "select * from subscription where id = (?) and " \
|
||||
"username = (?) limit 1", id, username do |rs|
|
||||
sub = Subscription.from_rs(rs).first?
|
||||
end
|
||||
end
|
||||
end
|
||||
sub
|
||||
end
|
||||
|
||||
def update_subscription_last_checked(id : Int64? = nil)
|
||||
MainFiber.run do
|
||||
get_db do |db|
|
||||
if id
|
||||
db.exec "update subscription set last_checked = (?) where id = (?)",
|
||||
Time.utc.to_unix, id
|
||||
else
|
||||
db.exec "update subscription set last_checked = (?)",
|
||||
Time.utc.to_unix
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def close
|
||||
MainFiber.run do
|
||||
unless @db.nil?
|
||||
|
@ -107,25 +107,6 @@ macro get_sort_opt
|
||||
end
|
||||
end
|
||||
|
||||
# Returns an authorized client
|
||||
def get_client(username : String) : MangaDex::Client
|
||||
token, expires = Storage.default.get_md_token username
|
||||
|
||||
unless expires && token
|
||||
raise "No token found for user #{username}"
|
||||
end
|
||||
|
||||
client = MangaDex::Client.from_config
|
||||
client.token = token
|
||||
client.token_expires = expires
|
||||
|
||||
client
|
||||
end
|
||||
|
||||
def get_client(env) : MangaDex::Client
|
||||
get_client get_username env
|
||||
end
|
||||
|
||||
module HTTP
|
||||
class Client
|
||||
private def self.exec(uri : URI, tls : TLSContext = nil)
|
||||
|
@ -5,8 +5,7 @@
|
||||
<button class="uk-button uk-button-default" @click="load()" :disabled="loading">Refresh Queue</button>
|
||||
<button class="uk-button uk-button-default" x-show="paused !== undefined" x-text="paused ? 'Resume Download' : 'Pause Download'" @click="toggle()" :disabled="toggling"></button>
|
||||
</div>
|
||||
<div class="uk-overflow-auto">
|
||||
<table class="uk-table uk-table-striped">
|
||||
<table class="uk-table uk-table-striped uk-overflow-auto">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Chapter</th>
|
||||
@ -50,7 +49,6 @@
|
||||
</td>
|
||||
|
||||
<td x-text="`${job.plugin_id || ''}`"></td>
|
||||
|
||||
<td>
|
||||
<a @click="jobAction('delete', $event)" uk-icon="trash" uk-tooltip="Delete"></a>
|
||||
<template x-if="job.status_message.length > 0">
|
||||
@ -61,7 +59,7 @@
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% content_for "script" do %>
|
||||
|
@ -43,10 +43,7 @@
|
||||
<p x-text="`Author: ${data.author}`"></p>
|
||||
</div>
|
||||
<div class="uk-form-stacked uk-width-1-2@s" id="filters">
|
||||
<p class="uk-text-lead uk-margin-remove-bottom">
|
||||
<span>Filter Chapters</span>
|
||||
<button class="uk-icon-button uk-align-right" uk-icon="rss" uk-tooltip="Subscribe" x-show="searchAvailable" @click="subscribe()"></button>
|
||||
</p>
|
||||
<p class="uk-text-lead uk-margin-remove-bottom">Filter Chapters</p>
|
||||
<p class="uk-text-meta uk-margin-remove-top" x-text="`${chapters.length} chapters found`"></p>
|
||||
<div class="uk-margin">
|
||||
<label class="uk-form-label">Language</label>
|
||||
@ -96,8 +93,7 @@
|
||||
<p class="uk-text-meta">Click on a table row to select the chapter. Drag your mouse over multiple rows to select them all. Hold Ctrl to make multiple non-adjacent selections.</p>
|
||||
</div>
|
||||
<p x-text="`Mango can only list ${chaptersLimit} chapters, but we found ${chapters.length} chapters. Please use the filter options above to narrow down your search.`" x-show="chapters.length > chaptersLimit"></p>
|
||||
<div class="uk-overflow-auto">
|
||||
<table class="uk-table uk-table-striped" x-show="chapters.length <= chaptersLimit">
|
||||
<table class="uk-table uk-table-striped uk-overflow-auto" x-show="chapters.length <= chaptersLimit">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
@ -133,7 +129,6 @@
|
||||
</template>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal" class="uk-flex-top" uk-modal="container: false">
|
||||
<div class="uk-modal-dialog uk-margin-auto-vertical">
|
||||
@ -147,7 +142,7 @@
|
||||
<img uk-img data-width data-height :src="candidateManga.mainCover" style="width:100%;margin-bottom:10px;">
|
||||
<a :href="`<%= mangadex_base_url %>/manga/${candidateManga.id}`" x-text="`ID: ${candidateManga.id}`" class="uk-link-muted"></a>
|
||||
</div>
|
||||
<div class="uk-width-2-3@s">
|
||||
<div class="uk-width-2-3@s" uk-overflow-auto>
|
||||
<p x-text="candidateManga.description"></p>
|
||||
</div>
|
||||
</div>
|
||||
@ -162,9 +157,6 @@
|
||||
<% content_for "script" do %>
|
||||
<%= render_component "moment" %>
|
||||
<%= render_component "jquery-ui" %>
|
||||
<script>
|
||||
const mangadex_base_url = "<%= mangadex_base_url %>";
|
||||
</script>
|
||||
<script src="<%= base_url %>js/alert.js"></script>
|
||||
<script src="<%= base_url %>js/download.js"></script>
|
||||
<% end %>
|
||||
|
@ -20,7 +20,6 @@
|
||||
<li><a href="<%= base_url %>download">MangaDex</a></li>
|
||||
<li><a href="<%= base_url %>download/plugins">Plugins</a></li>
|
||||
<li><a href="<%= base_url %>admin/downloads">Download Manager</a></li>
|
||||
<li><a href="<%= base_url %>download/subscription">Subscription Manager</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<% end %>
|
||||
@ -54,7 +53,6 @@
|
||||
<li><a href="<%= base_url %>download/plugins">Plugins</a></li>
|
||||
<li class="uk-nav-divider"></li>
|
||||
<li><a href="<%= base_url %>admin/downloads">Download Manager</a></li>
|
||||
<li><a href="<%= base_url %>download/subscription">Subscription Manager</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
|
@ -3,8 +3,7 @@
|
||||
<div x-show="!empty">
|
||||
<p>The following items were present in your library, but now we can't find them anymore. If you deleted them mistakenly, try to recover the files or folders, put them back to where they were, and rescan the library. Otherwise, you can safely delete them and the associated metadata using the buttons below to free up database space.</p>
|
||||
<button class="uk-button uk-button-danger" @click="rmAll()">Delete All</button>
|
||||
<div class="uk-overflow-auto">
|
||||
<table class="uk-table uk-table-striped">
|
||||
<table class="uk-table uk-table-striped uk-overflow-auto">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
@ -33,7 +32,6 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% content_for "script" do %>
|
||||
|
Loading…
x
Reference in New Issue
Block a user