{"id":23577149,"url":"https://github.com/eggpi/xmms2-autopilot","last_synced_at":"2025-11-02T08:30:31.436Z","repository":{"id":5916683,"uuid":"7136103","full_name":"eggpi/xmms2-autopilot","owner":"eggpi","description":"A xmms2 client that builds smart playlists","archived":false,"fork":false,"pushed_at":"2012-12-31T14:16:00.000Z","size":156,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-15T20:55:42.987Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eggpi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-12-12T19:13:45.000Z","updated_at":"2015-08-02T04:16:38.000Z","dependencies_parsed_at":"2022-08-03T00:00:26.886Z","dependency_job_id":null,"html_url":"https://github.com/eggpi/xmms2-autopilot","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eggpi%2Fxmms2-autopilot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eggpi%2Fxmms2-autopilot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eggpi%2Fxmms2-autopilot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eggpi%2Fxmms2-autopilot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eggpi","download_url":"https://codeload.github.com/eggpi/xmms2-autopilot/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239389576,"owners_count":19630310,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-26T22:27:00.374Z","updated_at":"2025-11-02T08:30:31.369Z","avatar_url":"https://github.com/eggpi.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# xmms2-autopilot\n\nThis repository contains a few ideas I've been dabbling with in the past days\nregarding making my xmms2 playlists smarter. I'm sort of happy with the results\nso far, although there's a lot of experimenting left to do with parameters for\nthe model I used and long time usage.\n\nBasically, what I'm trying to do here is, given a currently playing song,\nrecommend the next song to be added to the playlist using information taken\nfrom previous playlist manipulation.\n\nFor example, given that I usually listen to song B after song A, and then\nsometimes C and D after B (ignore numbers for now):\n\n                  1\n                 --\u003e C\n           2    /\n    ... A ---\u003e B\n                \\ 2\n                 --\u003e D ...\n\nit stands to reason that, the next time I hear song A, I may want to hear B, or\neven C or D next.\n\n## Recommending songs in 6 paragraphs and a TL;DR\n\nI attempted to model these listening patterns as a directed graph like the one\n(poorly) drawn above. When song A is played,  the nodes not too far from node A\nare candidates for being played next, so one of them is chosen randomly. In\nthis model, edges have weights that reflect how closely related two songs are\n-- the weight of the edge from A to B is the number of times B has been played\nafter A, namely 2 --, and these weights are used to weight the probability of\nchoosing an individual candidate.\n\nIn the example above, the candidates for next song when A is playing would be B,\nC, and D, with weights (normalized by distance to A) 2/1 = 2, 1/2 = 0.5 and\n2/2 = 1, respectively. This means B is four times as likely to be chosen as C,\nand twice as likely as D. I also add in a random node E into the mix, with\nminimum weight among other candidates (in this case 0.5), which makes it as\nlikely as being chosen as C.\n\nIf traversing the neighborhood of a node N does not yield enough candidates, one\nof the node's predecessors (that is, a node that has an edge leading to N) is\nchosen, and the candidates taken from its neighborhood are considered as well.\nThe predecessor node is chosen as the one whose edge to N has the largest\nweight. This strategy helps integrate new leaf nodes (that don't have a\nneighborhood) into the graph faster.\n\nIn the example above, applying this strategy makes D a candidate for C, since it\nis connected to C's only predecessor B.\n\nThe graph is built by using positive and negative examples of nodes that go\ntogether. If it is determined that B could follow A, the edge A -\u003e B is created\nwith weight 1 if it doesn't exist, or its weight is incremented if it exists.\nLikewise, the weight is decremented (and the edge is removed when the weight\nreaches 0) whenever it is determined that B should not follow A.\n\nIn the example above, if D is chosen as the next song after A, and the user\napproves this choice, a positive feedback could be given, which in turn creates\nan edge A -\u003e D. This, of course, makes D's neighborhood reachable from A in the\nnext time we need candidates for it.\n\n**TL;DR**: Build a directed weighted graph, songs are nodes, edges connect\nsongs that should follow one another. Add/increment edges with positive\nfeedbacks from the outside, remove/decrement with negative feedbacks. Pick next\nsong randomly from the neighborhood of the current song, with probabilities weighted\nby edge weights and node distance.\n\n## The code\n\nThis repository contains two files: recommend.py and autopilot.py.\n\nreccommend.py implements the graph algorithms described above. It exposes three\nmain functions:\n\n    positive(u, v)\n    Add positive feedback from node u to node v in the graph.\n\n    negative(u, v)\n    Add negative feedback from node u to node v in the graph.\n\n    next(u, default = None)\n    Request a node to follow u from the graph, returns the default if none is\n    found.\n\nautopilot.py is a xmms2 client that maps playlist manipulation events to\npositive and negative feedbacks, and fills the playlist with songs using the\nalgorithms above.\n\nBasically, whenever a song is added to a playlist or moved inside it, that's\ntranslated into a positive feedback from the preceding song to it. When a song\nis removed, that's a negative feedback. Also, when a song is skipped right\nafter it started, that's a negative feedback from the preceding song to the\nskipped song.\n\nWhen a song starts playing, the next song is requested from the graph. If no\ncandidates are found, a random song from the medialib is used as default (and\nadded to the graph when it is added to the playlist).\n\nautopilot.py is very much a hack/work in progress (in fact, so is everything\nelse in this repository), and I'd love to hear more suggestions for mapping\nplaylist events to feedbacks, and also making it work more like pshuffle.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feggpi%2Fxmms2-autopilot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feggpi%2Fxmms2-autopilot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feggpi%2Fxmms2-autopilot/lists"}