YouTube playlist steganography: hide secret messages inside YouTube playlists I have created this repo on GitHub and I have shown how this software works through a video.

If you have time, please visit the repo and read the files. I'll post some relevant snippets below, but if you can quickly skim over the whole thing, that would be great.

I'm new to Python so I'm sure there are some things in the code below that may not be best code practice. If you spot anything off, please let me know.

file yousecret.py:

I don't see many people writing Tkinter .grid() calls in this fashion so I'm thinking there may be some more practical way to do this. Also, the outcome looks like something from 1995, so I also wish I could give it a modern look.

enc_userkeys_label.grid(row=0,column=0)
enc_userkeys.grid(row=0,column=1)
enc_userkeys_clear.grid(row=0,column=2)
enc_sourcetext_label.grid(row=1,column=0)
enc_sourcetext.grid(row=1,column=1)
enc_sourcetext_clear.grid(row=1,column=2)
enc_button.grid(row=2,column=1)


file ysdecode.py:

What follows below feels like C code, I believe there must be a shorter and faster way to write this function in Python.

def getsum(addrlist):
    alladdr = []
    sumlists = []
    for addr in addrlist:
        final = []
        temp = []
        switch = True
        for url in addr:
            if switch:
                temp.append(url[0])
                switch = False
            elif not switch:
                temp.append(url[-1])
                switch = True
                final.append(tuple(temp))
                temp = []
        alladdr.append(tuple(final))
    for addr in alladdr:
        temp = []
        for pair in addr:
            for bitpair in BITARRAY:
                if pair == bitpair:
                    temp.append(BITARRAY.index(bitpair))
                    continue
        sumlists.append(tuple(temp)) 
    return sumlists


The addrlist parameter is a list of tuples, like this:

addrlist = [ ('wDzN2SQ8dCs', 'NLQf-Q8zlG0'), ('EhFPMTWSsso', 'wf1laG5Jp34') ] 


BITARRAY is a global variable that is also a list of tuples.

for i in '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz':
    for j in '048AEIMQUYcgkosw':
        BITARRAY.append((i,j))
Style

In any significant project, especially one that you are sharing through GitHub, it is important to write docstrings for each function.  You haven't written any.

It is implied by the PEP 8 official style guide that functions should be named using lower_case_with_underscores and constants should be named using UPPER_CASE_WITH_UNDERSCORES.  I would recommend renaming BITARRAY → BIT_ARRAY and getsum() → get_sum(), because pythonisnotgermanorfinnish.

Implementation

Whenever you build a list by starting with an empty list and appending to it in a loop, you'll almost certainly want to write a list comprehension or a generator expression instead.  That way, you describe the result "all at once" using a single statement.

from string import digits, ascii_uppercase, ascii_lowercase

INIT_CHARS = '-' + digits + ascii_uppercase + '_' + ascii_lowercase
FINAL_CHARS = '048AEIMQUYcgkosw'
BIT_ARRAY = sum(([tuple((a, b)) for a in INIT_CHARS] for b in FINAL_CHARS), [])


The sum() function above is used to concatenate lists.  That expression is a bit nasty.  You can write it better using itertools.product(), which is exactly what we need:

from itertools import product
from string import digits, ascii_uppercase, ascii_lowercase

INIT_CHARS = '-' + digits + ascii_uppercase + '_' + ascii_lowercase
FINAL_CHARS = '048AEIMQUYcgkosw'
BIT_ARRAY = list(product(INIT_CHARS, FINAL_CHARS))


Note, however, that it would be better not to define your BITARRAY at all, if your only goal is to find the index of a particular pair of characters.  Instead of BITARRAY.index(…), it would be more efficient to do a little arithmetic:

def numeric_value(init_char, final_char):
    """
    Given character init_char (one of the characters [-0-9A-Z_a-z]) and
    character final_char (one of the characters [048AEIMQUYcgkosw]),
    deterministically produce a numeric value from 0 to 1023, inclusive.
    """
    return INIT_CHARS.index(init_char) * len(FINAL_CHARS) + \
           FINAL_CHARS.index(final_char)


Based on similar principles, I would write this function:

def get_sum(video_ids):
    """
    Compute a tuple of numbers for the given YouTube video IDs.

    The videos IDs are taken two at a time.  From each pair, the initial
    character of the first ID and the final character of the second ID are
    taken.  Those two characters are mapped a numeric value between 0 and 1023.

    If there are an odd number of video IDs, the last one is ignored.
    """
    return tuple(
        numeric_value(a[0], b[-1]) for a, b in zip(*[iter(video_ids)] * 2)
    )


The zip(*[iter(video_ids)] * 2) expression above is a slick way to split the video_ids into pairs.  It comes from the grouper() example in the itertools recipes.

Note that your original getsum(addrlist) function is actually equivalent1 to

def getsum(addrlist):
    return [get_sum(playlist) for playlist in addrlist]


I recommend splitting the work this way instead, so that you don't end up with an excessively nested list comprehension.



1 Well, it's not exactly equivalent, in that your BITARRAY lookup silently ignores pairs of characters that do not conform to the ([-0-9A-Z_a-z], [048AEIMQUYcgkosw]) scheme, whereas numeric_value(…) would raise a ValueError.