lervag/apy

Feat: reposition new cards

AdrienLemaire opened this issue · 16 comments

Can we add a r: Reposition card option to the apy editor ?

Reviewing note 1 of 5
c: Continue        e: Edit            a: Add new         d: Delete
m: Toggle markdown *: Toggle marked   z: Toggle suspend  p: Toggle pprint
F: Clear flags     C: Show card names f: Show images     E: Edit CSS
s: Save and stop   x: Abort           r: Reposition card

This is the equivalent of:

If I clicked OK, that would reposition the card from no. 13 to no. 1, and shift the position of other cards.

This is a feature that I use daily, by modifying a pre-existing deck as I study Japanese kanjis with a book.

Can we add a r: Reposition card option to the apy editor ?

Perhaps. I don't use this feature myself, so I'm not fully sure how it works. If I added it, how would it work? That is, after typing "r", what should follow?

It would help if you could provide some examples/ideas for how the "menu" would look. Do you need both the "Start position", "Step", "Randomize order", and "Shift position of existing cards" choices? What would be the most simple, useful version (as a starting point)?

I'm only using the "start position" field, keeping the default values as is (including shift position of existing cards checked).

I did some research, here's what I've found.
Given that I want to reposition my card in the deck "Kanji in Context", I first need to find its id:

sqlite> select json_extract(json_each.value, '$.id') from col, json_each(col.decks) where json_extract(json_each.value, '$.name') = 'Kanji in Context';
json_extract(json_each.value, '$.id')
-------------------------------------
1

Then, let's check the first 20 cards in that deck ordered by due

sqlite> select id, due from cards where did=1 order by due limit 20;
id             due
-------------  ---
1475723866960  1
1467087354096  2
1475723699162  3
1599706392301  4
1599706392299  5
1475721398742  6
1475721327551  7
1475720828663  8
1475720736358  9
1475720690910  10
1599697019758  11
1475723785850  12
1475720423082  13
1475720179370  15
1475719893504  16
1599440484228  36
1599697019759  37
1596895920926  38
1599441119940  39
1476233067633  40

As a test, I'm now going to Anki to reposition card id=1475719893504 due=16 as due=1

Checking back in the db:

sqlite> select id, due from cards where did=1 order by due limit 20;
id             due
-------------  ---
1475719893504  0
1475723866960  1
1467087354096  2
1475723699162  3
1599706392301  4
1599706392299  5
1475721398742  6
1475721327551  7
1475720828663  8
1475720736358  9
1475720690910  10
1599697019758  11
1475723785850  12
1475720423082  13
1475720179370  15
1599440484228  36
1599697019759  37
1596895920926  38
1599441119940  39
1476233067633  40

Arf, it didn't shift cards because I had no card with due=0. Trying again with id=1475720179370 due=15

sqlite> select id, due from cards where did=1 order by due limit 20;
id             due
-------------  ---
1475720179370  0
1475719893504  1
1475723866960  2
1467087354096  3
1475723699162  4
1599706392301  5
1599706392299  6
1475721398742  7
1475721327551  8
1475720828663  9
1475720736358  10
1475720690910  11
1599697019758  12
1475723785850  13
1475720423082  14
1599440484228  37
1599697019759  38
1596895920926  39
1599441119940  40
1476233067633  41

As expected, it only shifted the position of the first 14 cards.
The algorithm seems to be quite naive.

  1. Set the due position to your card
  2. Is there another card with that due value? increment its due date
  3. Repeat 2 until there is no card with the same due value as the current card.

Now that I think about it, maybe we don't need another editor menu option, but can just add that field in the review/edit view ?

# Note
nid: 1457936014121
model: Yomi_learn
deck: Perso::Languages::Japanese::Main
tags: leech, word
markdown: false
due: 15   <!--  <-- New row -->

When saving it, you can detect if due has changed or not, and run the algorithm accordingly.

I do not mind how the menu should look like :) As long as I can quickly reposition my cards ^^'

I'm not 100% sure about this one, for one simple reason: I'm afraid of screwing up something important wrt. the review algorithm.

For instance, can not multiple cards easily share the same due "date"? Would I not need to take into account the value of the "number of new cards/day" option?

Btw, you are clearly much more familiar with sqlite and SQL/databases than me. I'm curious, how do you inspect the database directly? Something like sqlite3 collection.anki2?

For instance, can not multiple cards easily share the same due "date"? Would I not need to take into account the value of the "number of new cards/day" option?

Well, I wouldn't think much about it. If 2 cards have the same due=10 value, then just bump both of them to due=11 ? ^^

I'm curious, how do you inspect the database directly? Something like sqlite3 collection.anki2?

I thought for a second "How did he build this tool without inspecting the db ?". But it looks like you wrote a wrapper around the anki and apq python packages, is that correct ?

Yes, I'm using the sqlite3 tool 👍

$ sqlite3 <profile>/collection.anki2
sqlite> .mode column
sqlite> .headers on
sqlite> .tables
sqlite> pragma table_info('cards')
sqlite> .help

For instance, can not multiple cards easily share the same due "date"? Would I not need to take into account the value of the "number of new cards/day" option?

Well, I wouldn't think much about it. If 2 cards have the same due=10 value, then just bump both of them to due=11 ? ^^

Perhaps I misinterpret the meaning of due here. Does due have a different meaning for new cards? Perhaps it only specifies the order in which cards are to be reviewed/added, not the actual due time.

Also, apy review is centered around notes, while the due dates are card specific. So I think we would need a new command, something like apy set-due or apy reposition. apy reposition CID NEWDUE could work, perhaps?

I thought for a second "How did he build this tool without inspecting the db ?". But it looks like you wrote a wrapper around the anki and apq python packages, is that correct ?

Haha, yes. I've used the anki python package, mainly. It does bring some benefits, like that LaTeX stuff is generated automatically, and so on. But I should probably learn more about databases in general!

Yes, I'm using the sqlite3 tool +1

$ sqlite3 <profile>/collection.anki2
sqlite> .mode column
sqlite> .headers on
sqlite> .tables
sqlite> pragma table_info('cards')
sqlite> .help

Thanks! Immediate copy to my notes, I'll add some Anki cards... :)

Perhaps I misinterpret the meaning of due here. Does due have a different meaning for new cards? Perhaps it only specifies the order in which cards are to be reviewed/added, not the actual due time.

You're probably right. While the "due" column in the Anki browser shows numbers for new cards and dates for learnt cards, in the db, it's just an integer. And I've observed that the integer matches the number shown for new cards in the browser.

Also, apy review is centered around notes, while the due dates are card specific. So I think we would need a new command, something like apy set-due or apy reposition. apy reposition CID NEWDUE could work, perhaps?

Right... I often find myself spacing out cloze cards (eg a note has 3 cards, and I'll reposition them at due=0, due=40 and due=80, so that I learn them on different days.
If you could output some more info on save, like

2 notes created:
* <nid1> with one card
   * <cid1>
* <nid2> with 2 cards
    * <cid2>
    * <cid3>

Then I should be able to copy the ids and call apy reposition cid newdue.

I could even auto-tag my new cards, then make a script to reposition cards of tag & remove tag...

Also, apy review is centered around notes, while the due dates are card specific

@lervag from what I can observe, the apy review is going through cards, not notes

The title should be

- Reviewing note 4 of 4
+ Reviewing card 4 of 4

Because I'm seeing 1 basic note and 1 cloze containing 3 cards
Idem for apy list

You're probably right. While the "due" column in the Anki browser shows numbers for new cards and dates for learnt cards, in the db, it's just an integer. And I've observed that the integer matches the number shown for new cards in the browser.

In case you were not aware of it, The AnkiDroid project has a good reference on the Anki database. Thought you might find it interesting.

@lervag from what I can observe, the apy review is going through cards, not notes
...
Because I'm seeing 1 basic note and 1 cloze containing 3 cards
Idem for apy list

No, apy review is going through notes. The interface does not really make sense on a card level. However, you are right in that there was a bug where a note was repeated unnecessarily as many times as there are cards. I'm pushing a fix now.


So, to summarize our discussion, it seems these are the relevant tasks:

  • Add more output when notes are created
  • Add command apy reposition CID NEWDUE

Do you agree?

In case you were not aware of it, The AnkiDroid project has a good reference on the Anki database. Thought you might find it interesting.

❤️

  • Add command apy reposition CID NEWDUE
    Do you agree?

Yes. It would also be nice to see the due info of cards in the apy list -v output. This will help to confirm/assess whether a card needs to be repositioned or not.
Thank you so much for that.

Ok, I've added an initial version of this now. Please test and provide some feedback. I'm curious if perhaps the query type of argument might be relevant here also, similar to the apy list and apy review commands?

Please make sure to backup your database before testing, as I've only barely tested this now. I think it should work, but I might have missed something important.

Note, I forgot to tag the commits with this issue thread, but it should be pushed now.

Please make sure to backup your database before testing, as I've only barely tested this now.

Anki always auto-backup whenever we close or sync the app. Would be nice to add this feature to apy sync as well :)

I'm curious if perhaps the query type of argument might be relevant here also

Definitely. I've taken the habit these past days to tag my cards fixme and use that query to reposition them from the anki browser, so a apy reposition tag:fixme 0 && apy tag -r fixme tag:fixme would be very efficient.


Thanks for the colors !

It looks fine to me 🎉

Anki always auto-backup whenever we close or sync the app. Would be nice to add this feature to apy sync as well :)

Good idea. I suggest you open a new issue for it. I will need to determine how the backup actually works. I would think it better to add a apy backup ... command, and possibly an option to specify "autobackup".

Definitely. I've taken the habit these past days to tag my cards fixme and use that query to reposition them from the anki browser, so a apy reposition tag:fixme 0 && apy tag -r fixme tag:fixme would be very efficient.

Ok, I'll update and push soon. I'm curious, though: What is your workflow that makes you want to reposition your cards so often? That is, I tend to add perhaps 25-50 cards a week, and I don't really need repositioning (I just add at random). Is the difference with you that you are working on a different scale and want more control over which cards are added at which time?

Thanks for the colors !

It started to be somewhat difficult to quickly parse the output, so I figured some color would help. Glad you like it!

It looks fine to me

Great!

I think this issue should be resolved now.

What is your workflow that makes you want to reposition your cards so often? That is, I tend to add perhaps 25-50 cards a week, and I don't really need repositioning (I just add at random).

I'm studying the japanese kanji from a book and reusing a shared deck with thousands of notes that I'm modifying. Whenever I learn a new kanji, I search for new cards that contain it, modify them, then reposition them so that I can learn them next.
I'm learning between 200 and 300 new cards a week.

Indeed, for other decks, since I create all cards and learn them as soon as I make them, I do not have that need for repositioning.

Thank you so much for making that feature. Apy is the best ❤️

I'm studying the japanese kanji from a book and reusing a shared deck with thousands of notes that I'm modifying. Whenever I learn a new kanji, I search for new cards that contain it, modify them, then reposition them so that I can learn them next.
I'm learning between 200 and 300 new cards a week.

Cool!

Indeed, for other decks, since I create all cards and learn them as soon as I make them, I do not have that need for repositioning.

Thank you so much for making that feature. Apy is the best heart

My pleasure, I'm glad you like it! :D