working (feature complete) news_fetch
This commit is contained in:
parent
afead44d6c
commit
d3d44dcdc9
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB |
@ -1,63 +0,0 @@
|
|||||||
html, body {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
color: #333;
|
|
||||||
margin: 0;
|
|
||||||
padding: 8px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: rgb(0,100,200);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:visited {
|
|
||||||
color: rgb(0,80,160);
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
input, button, select, textarea {
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
-webkit-padding: 0.4em 0;
|
|
||||||
padding: 0.4em;
|
|
||||||
margin: 0 0 0.5em 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:disabled {
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
color: #333;
|
|
||||||
background-color: #f4f4f4;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:disabled {
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:not(:disabled):active {
|
|
||||||
background-color: #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:focus {
|
|
||||||
border-color: #666;
|
|
||||||
}
|
|
@ -2,10 +2,15 @@
|
|||||||
import PDFView from './PDFView.svelte';
|
import PDFView from './PDFView.svelte';
|
||||||
import ArticleStatus from './ArticleStatus.svelte';
|
import ArticleStatus from './ArticleStatus.svelte';
|
||||||
import ArticleOperations from './ArticleOperations.svelte';
|
import ArticleOperations from './ArticleOperations.svelte';
|
||||||
|
|
||||||
|
import Toast from './Toast.svelte';
|
||||||
|
|
||||||
|
|
||||||
let current_id = 0;
|
let current_id = 0;
|
||||||
|
|
||||||
const updateInterface = (async () => {
|
let interfaceState = updateInterface()
|
||||||
|
|
||||||
|
async function updateInterface () {
|
||||||
let url = '';
|
let url = '';
|
||||||
if (current_id == 0) {
|
if (current_id == 0) {
|
||||||
url = '/api/article/first';
|
url = '/api/article/first';
|
||||||
@ -19,12 +24,14 @@
|
|||||||
const article_response = await fetch(article_url);
|
const article_response = await fetch(article_url);
|
||||||
const article_data = await article_response.json();
|
const article_data = await article_response.json();
|
||||||
return article_data;
|
return article_data;
|
||||||
})()
|
}
|
||||||
|
|
||||||
|
function triggerUpdate () {
|
||||||
|
interfaceState = updateInterface();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#await updateInterface}
|
{#await interfaceState}
|
||||||
...
|
...
|
||||||
{:then article_data}
|
{:then article_data}
|
||||||
<div class="flex w-full h-screen gap-5 p-5">
|
<div class="flex w-full h-screen gap-5 p-5">
|
||||||
@ -33,7 +40,9 @@
|
|||||||
<div class="w-2/5">
|
<div class="w-2/5">
|
||||||
<ArticleStatus article_data={article_data}/>
|
<ArticleStatus article_data={article_data}/>
|
||||||
<div class="divider divider-vertical"></div>
|
<div class="divider divider-vertical"></div>
|
||||||
<ArticleOperations article_data={article_data}/>
|
<ArticleOperations article_data={article_data} callback={triggerUpdate}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/await}
|
{/await}
|
||||||
|
|
||||||
|
<Toast/>
|
@ -1,55 +1,85 @@
|
|||||||
<script>
|
<script>
|
||||||
import {fade} from 'svelte/transition';
|
|
||||||
|
|
||||||
export let article_data;
|
export let article_data;
|
||||||
|
export let callback;
|
||||||
|
window.focus()
|
||||||
|
import { addToast } from './Toast.svelte';
|
||||||
|
|
||||||
const actions = [
|
const actions = [
|
||||||
{name: 'Mark as good (and skip to next)', kbd: 'A'},
|
{name: 'Mark as good (and skip to next)', kbd: 'A'},
|
||||||
{name: 'Mark as bad (and skip to next)', kbd: 'B'},
|
{name: 'Mark as bad (and skip to next)', kbd: 'B'},
|
||||||
{name: 'Upload related file', kbd: 'R'},
|
{name: 'Upload related file', kbd: 'R', comment: "can be used multiple times"},
|
||||||
{name: 'Skip', kbd: 'ctrl'},
|
{name: 'Skip', kbd: 'S'},
|
||||||
]
|
]
|
||||||
|
|
||||||
const toast_states = {
|
|
||||||
'success' : {class: 'alert-success', text: 'Article updated successfully'},
|
|
||||||
'error' : {class: 'alert-error', text: 'Article update failed'},
|
|
||||||
}
|
|
||||||
let toast_state = {};
|
|
||||||
let toast_visible = false;
|
|
||||||
|
|
||||||
|
let fileInput = document.createElement('input');
|
||||||
|
fileInput.type = 'file';
|
||||||
|
|
||||||
|
fileInput.onchange = e => {
|
||||||
|
let result = (async () => {
|
||||||
|
uploadRelatedFile(e.target.files[0]);
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function onKeyDown(e) {apiAction(e.key)}
|
function onKeyDown(e) {apiAction(e.key)}
|
||||||
function apiAction(key) {
|
function apiAction(key) {
|
||||||
if (actions.map(d => d.kbd.toLowerCase()).includes(key.toLowerCase())){ // ignore other keypresses
|
if (actions.map(d => d.kbd.toLowerCase()).includes(key.toLowerCase())){ // ignore other keypresses
|
||||||
|
|
||||||
const updateArticle = (async() => {
|
const updateArticle = (async() => {
|
||||||
const response = await fetch('/api/article/' + article_data.id + '/set', {
|
let success
|
||||||
method: 'POST',
|
|
||||||
headers: {'Content-Type': 'application/json'},
|
|
||||||
body: JSON.stringify({
|
|
||||||
'action': key.toLowerCase(),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
const success = response.status == 200;
|
|
||||||
|
|
||||||
if (success){
|
|
||||||
showToast('success');
|
|
||||||
} else {
|
|
||||||
showToast('error');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (key.toLowerCase() == "s") {
|
||||||
|
addToast('success', "Article skipped")
|
||||||
|
callback()
|
||||||
|
return
|
||||||
|
} else if (key.toLowerCase() == "r") {
|
||||||
|
fileInput.click() // this will trigger a change in fileInput,
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
const response = await fetch('/api/article/' + article_data.id + '/set', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: JSON.stringify({
|
||||||
|
'action': key.toLowerCase(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
success = response.status == 200
|
||||||
|
}
|
||||||
|
if (success){
|
||||||
|
addToast('success')
|
||||||
|
callback()
|
||||||
|
} else {
|
||||||
|
addToast('error')
|
||||||
|
}
|
||||||
})()
|
})()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showToast(state){
|
|
||||||
toast_visible = true;
|
|
||||||
toast_state = toast_states[state];
|
|
||||||
setTimeout(() => {
|
|
||||||
toast_visible = false;
|
|
||||||
}, 1000)
|
|
||||||
|
|
||||||
|
|
||||||
|
async function uploadRelatedFile(file) {
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', file)
|
||||||
|
|
||||||
|
const response = await fetch('/api/article/' + article_data.id + '/set', {
|
||||||
|
method: 'POST',
|
||||||
|
body : formData,
|
||||||
|
})
|
||||||
|
|
||||||
|
const success = response.status == 200;
|
||||||
|
if (success){
|
||||||
|
const data = await response.json()
|
||||||
|
let fname = data.file_path
|
||||||
|
addToast('success', "File uploaded as " + fname)
|
||||||
|
} else {
|
||||||
|
addToast('error', "File upload failed")
|
||||||
|
}
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
@ -58,21 +88,22 @@
|
|||||||
<h2 class="card-title">Your options: (click on action or use keyboard)</h2>
|
<h2 class="card-title">Your options: (click on action or use keyboard)</h2>
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table w-full table-compact">
|
<table class="table w-full table-compact">
|
||||||
<!-- head -->
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
<th>Keyboard shortcut</th>
|
<th>Keyboard shortcut</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{#each actions as action}
|
{#each actions as action}
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><button on:click={() => apiAction(action.kbd)}>{ action.name }</button></td>
|
<td><button on:click={() => apiAction(action.kbd)}>{ action.name }</button></td>
|
||||||
<td><kbd class="kbd">{ action.kbd }</kbd></td>
|
<td><kbd class="kbd">
|
||||||
|
{ action.kbd }</kbd>
|
||||||
|
{#if action.comment}({ action.comment }){/if}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{/each}
|
{/each}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -80,14 +111,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Listen for keypresses -->
|
||||||
<svelte:window on:keydown|preventDefault={onKeyDown} />
|
<svelte:window on:keydown|preventDefault={onKeyDown} />
|
||||||
|
|
||||||
{#if toast_visible}
|
|
||||||
<div class="toast" transition:fade>
|
|
||||||
<div class="alert { toast_state.class }">
|
|
||||||
<div>
|
|
||||||
<span>{ toast_state.text }.</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
@ -2,13 +2,21 @@
|
|||||||
export let article_data;
|
export let article_data;
|
||||||
const status_items = [
|
const status_items = [
|
||||||
{name: 'Title', value: article_data.title},
|
{name: 'Title', value: article_data.title},
|
||||||
|
{name: 'Url', value: article_data.article_url},
|
||||||
|
{name: 'Source', value: article_data.source_name},
|
||||||
{name: 'Filename', value: article_data.file_name},
|
{name: 'Filename', value: article_data.file_name},
|
||||||
|
{name: 'Location', value: article_data.save_path},
|
||||||
{name: 'Language', value: article_data.language},
|
{name: 'Language', value: article_data.language},
|
||||||
{name: 'Authors', value: article_data.authors},
|
{name: 'Authors', value: article_data.authors},
|
||||||
{name: "Related", value: article_data.related},
|
{name: "Related", value: article_data.related},
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<div class="card bg-neutral-300 shadow-xl overflow-x-auto">
|
<div class="card bg-neutral-300 shadow-xl overflow-x-auto">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="card-title">Article overview:</h2>
|
<h2 class="card-title">Article overview:</h2>
|
||||||
@ -23,16 +31,18 @@
|
|||||||
{#each status_items as item}
|
{#each status_items as item}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{ item.name }</td>
|
<td>{ item.name }</td>
|
||||||
<!-- <td>Quality Control Specialist</td> -->
|
|
||||||
{#if item.value != ""}
|
{#if item.value != ""}
|
||||||
|
{#if item.name == "Url"}
|
||||||
|
<td class='bg-emerald-200'><a href="{ item.value }">{ item.value }</a></td>
|
||||||
|
{:else}
|
||||||
<td class='bg-emerald-200' style="white-space: normal; width:70%">{ item.value }</td>
|
<td class='bg-emerald-200' style="white-space: normal; width:70%">{ item.value }</td>
|
||||||
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<td class='bg-red-200'>{ item.value }</td>
|
<td class='bg-red-200'>not set</td>
|
||||||
{/if}
|
{/if}
|
||||||
</tr>
|
</tr>
|
||||||
{/each}
|
{/each}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
34
news_check/client/src/Toast.svelte
Normal file
34
news_check/client/src/Toast.svelte
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<script context="module">
|
||||||
|
import {fade} from 'svelte/transition';
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
|
||||||
|
let toasts = writable([])
|
||||||
|
|
||||||
|
export function addToast (type, message="") {
|
||||||
|
if (message == "") {
|
||||||
|
message = toast_states[type]["text"]
|
||||||
|
}
|
||||||
|
toasts.update((all) => [{"class" : toast_states[type]["class"], "text": message}, ...all]);
|
||||||
|
toasts = toasts;
|
||||||
|
setTimeout(() => {
|
||||||
|
toasts.update((all) => all.slice(0, -1));
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const toast_states = {
|
||||||
|
'success' : {class: 'alert-success', text: 'Article updated successfully'},
|
||||||
|
'error' : {class: 'alert-error', text: 'Article update failed'},
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="toast">
|
||||||
|
{#each $toasts as toast}
|
||||||
|
<div class="alert { toast.class }" transition:fade>
|
||||||
|
<div> <span>{ toast.text }.</span> </div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
@ -2,9 +2,6 @@ import App from './App.svelte';
|
|||||||
|
|
||||||
const app = new App({
|
const app = new App({
|
||||||
target: document.body,
|
target: document.body,
|
||||||
props: {
|
|
||||||
name: 'world'
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default app;
|
export default app;
|
@ -1,5 +1,7 @@
|
|||||||
from flask import Flask, send_from_directory, request
|
from flask import Flask, send_from_directory, request
|
||||||
|
import os
|
||||||
import configuration
|
import configuration
|
||||||
|
|
||||||
models = configuration.models
|
models = configuration.models
|
||||||
db = configuration.db
|
db = configuration.db
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
@ -30,9 +32,9 @@ def get_article_by_id(id):
|
|||||||
return article.to_dict()
|
return article.to_dict()
|
||||||
|
|
||||||
@app.route("/api/article/first")
|
@app.route("/api/article/first")
|
||||||
def get_article_first():
|
def get_article_first(min_id=0):
|
||||||
with db:
|
with db:
|
||||||
article = models.ArticleDownload.select(models.ArticleDownload.id).where(models.ArticleDownload.verified == 0).order_by(models.ArticleDownload.id).first()
|
article = models.ArticleDownload.select(models.ArticleDownload.id).where((models.ArticleDownload.verified == 0) & (models.ArticleDownload.id > min_id)).order_by(models.ArticleDownload.id).first()
|
||||||
return {"id" : article.id}
|
return {"id" : article.id}
|
||||||
|
|
||||||
@app.route("/api/article/<int:id>/next")
|
@app.route("/api/article/<int:id>/next")
|
||||||
@ -41,27 +43,44 @@ def get_article_next(id):
|
|||||||
if models.ArticleDownload.get_by_id(id + 1).verified == 0:
|
if models.ArticleDownload.get_by_id(id + 1).verified == 0:
|
||||||
return {"id" : id + 1}
|
return {"id" : id + 1}
|
||||||
else:
|
else:
|
||||||
return get_article_first()
|
return get_article_first(min_id=id) # if the current article was skipped, but the +1 is already verified, get_first will return the same article again. so specify min id.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/article/<int:id>/set", methods=['POST'])
|
@app.route("/api/article/<int:id>/set", methods=['POST'])
|
||||||
def set_article(id):
|
def set_article(id):
|
||||||
action = request.json['action']
|
try:
|
||||||
|
action = request.json.get('action', None)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Exception in set_article {e}")
|
||||||
|
action = None
|
||||||
with db:
|
with db:
|
||||||
article = models.ArticleDownload.get_by_id(id)
|
article = models.ArticleDownload.get_by_id(id)
|
||||||
if action == "a":
|
if action:
|
||||||
article.verified = 1
|
if action == "a":
|
||||||
elif action == "b":
|
article.verified = 1
|
||||||
article.verified = -1
|
elif action == "b":
|
||||||
elif action == "r":
|
article.verified = -1
|
||||||
article.set_related()
|
else: # implicitly action == "r":
|
||||||
article.save()
|
print(request.files)
|
||||||
return "ok"
|
file = request.files.get("file", None)
|
||||||
|
if file is None: # upload tends to crash
|
||||||
|
return "No file uploaded", 400
|
||||||
|
|
||||||
|
artname, _ = os.path.splitext(article.file_name)
|
||||||
|
fname = f"{artname} -- related_{article.related.count() + 1}.{file.filename.split('.')[-1]}"
|
||||||
|
fpath = os.path.join(article.save_path, fname)
|
||||||
|
print(fpath)
|
||||||
|
file.save(fpath)
|
||||||
|
article.set_related([fname])
|
||||||
|
return {"file_path": fpath}
|
||||||
|
|
||||||
|
article.save()
|
||||||
|
return "ok"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(host="0.0.0.0", port="80")
|
debug = os.getenv("DEBUG", "false") == "true"
|
||||||
|
app.run(host="0.0.0.0", port="80", debug=debug)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from peewee import PostgresqlDatabase
|
from peewee import PostgresqlDatabase
|
||||||
import configparser
|
import configparser
|
||||||
|
import time
|
||||||
|
|
||||||
main_config = configparser.ConfigParser()
|
main_config = configparser.ConfigParser()
|
||||||
main_config.read("/app/containerdata/config/news_fetch.config.ini")
|
main_config.read("/app/containerdata/config/news_fetch.config.ini")
|
||||||
@ -8,6 +9,7 @@ db_config = configparser.ConfigParser()
|
|||||||
db_config.read("/app/containerdata/config/db.config.ini")
|
db_config.read("/app/containerdata/config/db.config.ini")
|
||||||
|
|
||||||
cred = db_config["DATABASE"]
|
cred = db_config["DATABASE"]
|
||||||
|
time.sleep(10) # wait for the vpn to connect (can't use a healthcheck because there is no depends_on)
|
||||||
db = PostgresqlDatabase(
|
db = PostgresqlDatabase(
|
||||||
cred["db_name"], user=cred["user_name"], password=cred["password"], host="vpn", port=5432
|
cred["db_name"], user=cred["user_name"], password=cred["password"], host="vpn", port=5432
|
||||||
)
|
)
|
||||||
|
@ -2,8 +2,8 @@ import os
|
|||||||
import configparser
|
import configparser
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
import shutil
|
# import shutil
|
||||||
from datetime import datetime
|
# from datetime import datetime
|
||||||
from peewee import SqliteDatabase, PostgresqlDatabase
|
from peewee import SqliteDatabase, PostgresqlDatabase
|
||||||
from rich.logging import RichHandler
|
from rich.logging import RichHandler
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
"""Main coordination of other util classes. Handles inbound and outbound calls"""
|
"""Main coordination of other util classes. Handles inbound and outbound calls"""
|
||||||
|
from time import sleep
|
||||||
import configuration
|
import configuration
|
||||||
models = configuration.models
|
models = configuration.models
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
@ -110,7 +111,8 @@ class Dispatcher(Thread):
|
|||||||
logger.error("Dispatcher.incoming_request called with no arguments")
|
logger.error("Dispatcher.incoming_request called with no arguments")
|
||||||
return
|
return
|
||||||
|
|
||||||
if is_new or (article.file_name == "" and article.verified == 0):
|
if is_new or (article.file_name == "" and article.verified == 0) \
|
||||||
|
or (not is_new and len(self.workers_in) == 1): # this is for upload
|
||||||
# check for models that were created but were abandonned. This means they have missing information, most importantly no associated file
|
# check for models that were created but were abandonned. This means they have missing information, most importantly no associated file
|
||||||
# this overwrites previously set information, but that should not be too important
|
# this overwrites previously set information, but that should not be too important
|
||||||
ArticleWatcher(
|
ArticleWatcher(
|
||||||
@ -121,7 +123,6 @@ class Dispatcher(Thread):
|
|||||||
|
|
||||||
else: # manually trigger notification immediatly
|
else: # manually trigger notification immediatly
|
||||||
logger.info(f"Found existing article {article}. Now sending")
|
logger.info(f"Found existing article {article}. Now sending")
|
||||||
self.article_complete_notifier(article)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -142,6 +143,8 @@ if __name__ == "__main__":
|
|||||||
class PrintWorker:
|
class PrintWorker:
|
||||||
def send(self, article):
|
def send(self, article):
|
||||||
print(f"Uploaded article {article}")
|
print(f"Uploaded article {article}")
|
||||||
|
def keep_alive(self): # keeps script running, because there is nothing else in the main thread
|
||||||
|
while True: sleep(1)
|
||||||
|
|
||||||
articles = models.ArticleDownload.select().where(models.ArticleDownload.archive_url == "" or models.ArticleDownload.archive_url == "TODO:UPLOAD").execute()
|
articles = models.ArticleDownload.select().where(models.ArticleDownload.archive_url == "" or models.ArticleDownload.archive_url == "TODO:UPLOAD").execute()
|
||||||
logger.info(f"Launching upload to archive for {len(articles)} articles.")
|
logger.info(f"Launching upload to archive for {len(articles)} articles.")
|
||||||
@ -149,6 +152,9 @@ if __name__ == "__main__":
|
|||||||
dispatcher.workers_in = [{"UploadWorker": UploadWorker()}]
|
dispatcher.workers_in = [{"UploadWorker": UploadWorker()}]
|
||||||
dispatcher.workers_out = [{"PrintWorker": PrintWorker()}]
|
dispatcher.workers_out = [{"PrintWorker": PrintWorker()}]
|
||||||
dispatcher.start()
|
dispatcher.start()
|
||||||
|
for a in articles:
|
||||||
|
dispatcher.incoming_request(article=a)
|
||||||
|
PrintWorker().keep_alive()
|
||||||
|
|
||||||
else: # launch with full action
|
else: # launch with full action
|
||||||
try:
|
try:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user